Vault Error: 'wrapping token is not valid or does not exist' on Unwrap
Fix Vault response-wrapping failures: single-use unwrap semantics, expired wrap TTLs in CI, sys/wrapping/lookup and rewrap, cubbyhole storage, clock skew, and the rotation response when an unwrap fails unexpectedly.
- #vault
- #secrets
- #security-hardening
- #troubleshooting
- #errors
Stuck on this HashiCorp Vault error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Exact Error Message
$ vault unwrap hvs.CAESIJk3...
Error making API request.
URL: PUT https://vault.example.com:8200/v1/sys/wrapping/unwrap
Code: 400. Errors:
* wrapping token is not valid or does not exist
Depending on how the token was consumed you may instead see:
Error making API request.
URL: PUT https://vault.example.com:8200/v1/sys/wrapping/unwrap
Code: 400. Errors:
* wrapping token is not valid or does not exist
# or, when the token is valid but is not a wrapping token at all:
* wrapping token does not contain a wrapped response
What It Means
Response wrapping takes the response Vault was about to return, stores it inside a brand-new single-use token’s cubbyhole, and hands you only that token. The actual secret never travels to the requester in plaintext; it sits in Vault’s cubbyhole backend under a token that nobody else holds. vault unwrap exchanges that token for the stored response — and in doing so consumes and revokes it. The wrapping token is strictly single-use: the first unwrap succeeds, and every subsequent unwrap of the same token fails with wrapping token is not valid or does not exist.
That single error string covers three distinct situations, which is why it is confusing: the token was already unwrapped, the wrap TTL expired before anyone unwrapped it, or the token value is simply wrong (truncated, from another cluster, or from a different namespace). Vault deliberately does not distinguish between them in the error, because telling an attacker “this token existed but expired” leaks information. The important operational consequence is the security one: because unwrapping is single-use and self-revoking, a failed unwrap when you expected success is a genuine tamper signal. Either someone else got there first and read your secret, or the delivery path is broken. Both demand investigation, and the first demands rotation.
Common Causes
- The token was already unwrapped — often by a retry, a re-run of the same CI step, or a debugging command someone ran earlier.
- The wrap TTL was shorter than the real gap between issuing the token and consuming it (queued CI jobs, manual approval gates, cold-start workers).
- The token was logged, copied through a chat message, or echoed into build output, and something else consumed it first.
- Client and server clocks are skewed enough that the TTL appears already elapsed.
- The unwrap is being attempted against a different cluster, or in a different namespace than the one that issued the wrap.
- The value being passed is a normal service token rather than a wrapping token, so there is no wrapped response to return.
Diagnostic Commands
The critical first move is to look the token up without consuming it. sys/wrapping/lookup returns metadata only and does not unwrap:
vault write -format=json sys/wrapping/lookup token="hvs.CAESIJk3..." | jq '.data'
A live wrapping token returns something like:
{
"creation_path": "auth/approle/role/deployer/secret-id",
"creation_time": "2026-07-19T09:14:02.118374Z",
"creation_ttl": 120
}
Three useful facts come out of that: creation_path tells you what was wrapped (so you know what to rotate), creation_ttl tells you the wrap window in seconds, and creation_time lets you compute whether it should still be alive. If lookup itself returns wrapping token is not valid or does not exist, the token is already gone — consumed or expired — and you cannot recover the payload.
Check for clock skew between the client and the Vault servers, since a few minutes of drift will make short TTLs behave unpredictably:
date -u
curl -sI https://vault.example.com:8200/v1/sys/health | grep -i '^date:'
timedatectl status | grep -E 'synchronized|NTP service'
Confirm you are pointed at the right cluster and namespace. A wrapping token issued in one namespace cannot be unwrapped from another:
echo "$VAULT_ADDR $VAULT_NAMESPACE"
vault status -format=json | jq '{cluster_name, sealed, version}'
If the connection itself is failing rather than the unwrap, isolate that first — a TLS trust failure produces a transport error, not this 400. You can add -tls-skip-verify to a single vault status call as a temporary diagnostic only to confirm trust is the variable, then fix the CA bundle properly and remove the flag; never ship it in a pipeline.
Finally, check your audit devices for who unwrapped it. The audit log is the authoritative answer to “did someone else consume this?”:
vault audit list -detailed
sudo grep -F 'sys/wrapping/unwrap' /var/log/vault/audit.log | tail -20 | jq -c '{time, path: .request.path, remote: .request.remote_address, err: .error}'
If audit logging is not enabled, you have no way to answer that question — see Vault error: audit device blocking for the trade-offs of running audit devices in the request path.
Step-by-Step Resolution
- Stop and classify the failure before re-issuing anything. If
sys/wrapping/lookupsays the token does not exist and your pipeline never successfully unwrapped it, treat the wrapped secret as compromised and rotate it. Do not simply re-wrap and continue.
vault write -format=json sys/wrapping/lookup token="$WRAP_TOKEN" || echo "CONSUMED OR EXPIRED - rotate"
- Re-issue the secret with a wrap TTL that matches the real end-to-end latency of the consumer.
-wrap-ttlworks on any read or write:
# wrap a KV read
vault kv get -wrap-ttl=300s secret/app/config
# wrap an AppRole secret-id for delivery to a worker
vault write -wrap-ttl=300s -f auth/approle/role/deployer/secret-id
The response contains a wrap_info block rather than the secret itself:
{
"wrap_info": {
"token": "hvs.CAESIJk3...",
"accessor": "MEyBSlLxfHKZAOPuJYUuUpBM",
"ttl": 300,
"creation_time": "2026-07-19T09:14:02.118374Z",
"creation_path": "auth/approle/role/deployer/secret-id"
}
}
- Unwrap exactly once, in the consumer, and fail loudly on error. Never retry an unwrap that returned this error — the retry cannot succeed, and swallowing it hides the tamper signal:
set -euo pipefail
SECRET_ID=$(vault unwrap -field=secret_id "$WRAP_TOKEN") || {
echo "FATAL: unwrap failed - secret may be compromised, rotating" >&2
exit 1
}
- If the token is still alive but the consumer will be delayed, rewrap it. Rewrapping issues a new wrapping token for the same payload with a fresh TTL and invalidates the old one, without ever exposing the secret:
vault write -format=json sys/wrapping/rewrap token="$WRAP_TOKEN" | jq -r '.wrap_info.token'
- Wire the AppRole delivery pattern correctly: a trusted orchestrator holds the role ID and requests a wrapped secret ID, and only the workload unwraps it. The orchestrator never sees the secret ID, and the workload proves it was first to unwrap:
# Trusted orchestrator
ROLE_ID=$(vault read -field=role_id auth/approle/role/deployer/role-id)
WRAP=$(vault write -wrap-ttl=120s -f -format=json auth/approle/role/deployer/secret-id \
| jq -r '.wrap_info.token')
# Workload (receives only $WRAP over the injection channel)
SECRET_ID=$(vault unwrap -field=secret_id "$WRAP")
vault write -field=token auth/approle/login role_id="$ROLE_ID" secret_id="$SECRET_ID"
- Close the loop on clock skew and TTL sizing. Enable NTP everywhere and set the wrap TTL from measured p99 delivery time with headroom, not from a guess:
sudo timedatectl set-ntp true
timedatectl status | grep 'System clock synchronized'
Prevention
- Size wrap TTLs from measured worst-case delivery latency, and prefer
sys/wrapping/rewrapover long TTLs when a queue may delay the consumer. - Never log, print, or echo wrapping tokens; treat them as equivalent to the secret they protect until unwrapped.
- Make unwrap a fail-closed operation in every pipeline — an unexpected unwrap failure should page, not retry.
- Use
sys/wrapping/lookupfor any diagnostic inspection, so troubleshooting never consumes the token. - Keep NTP enforced on both Vault servers and clients so short TTLs behave deterministically.
- Enable audit devices so you can prove whether a wrapping token was consumed and from where.
Related Errors
permission deniedon unwrap — the caller’s policy deniessys/wrapping/unwrap, distinct from an invalid token.wrapping token does not contain a wrapped response— a normal service token was passed where a wrapping token was expected.cipher: message authentication failed— a Transit decrypt problem, not a wrapping problem. See Vault error: Transit cipher decrypt failed.Vault is sealed— the cluster cannot serve any request, including unwrap. See Vault error: auto-unseal KMS access denied.
Frequently Asked Questions
Can I unwrap the same token twice? No. Unwrapping consumes and revokes the token by design, so the second attempt always fails. If two consumers need the payload, unwrap once and distribute the result through your own secure channel, or issue two separately wrapped responses.
Does sys/wrapping/lookup consume the token? No — that is exactly why it exists. It returns creation_ttl, creation_time, and creation_path without unwrapping, so you can verify a token is alive and identify what was wrapped without burning it.
My unwrap failed and I know the pipeline never ran. What now? Assume the secret was read by someone else. Rotate the underlying credential immediately, check the audit log for the unwrap event’s source address, and only then re-issue a new wrapped response. An unexplained unwrap failure is a tamper signal, not a transient error.
Where is the wrapped data actually stored? In the cubbyhole of the single-use wrapping token itself. Cubbyhole storage is scoped to one token and destroyed when that token is revoked or expires, which is what makes the payload unrecoverable after a failed unwrap. For more secret-delivery fixes, see the Vault guides.
Fixed it? Get 500 HashiCorp Vault & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.