Skip to content
🎉 Launch sale:50% off everything over $22 — automatically applied at checkout· ends Aug 2Shop the sale →
DevOps AI ToolKit
Newsletter
All guides
AI for HashiCorp Vault By James Joyner IV · · 9 min read Last reviewed Jul 2026

Vault Error: 'No value found at secret/myapp/config' on KV Reads

Quick answer

Fix Vault's 'No value found at' error: tell KV v1 from KV v2, handle the injected data/ path segment, check namespaces, and recover soft-deleted secret versions.

  • #vault
  • #secrets
  • #security-hardening
  • #troubleshooting
  • #errors
Free toolkit

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 kv get secret/myapp/config
No value found at secret/data/myapp/config

Reading the same path through the raw API returns an empty success rather than an error, which is why this often shows up as a null in application code instead of a failure:

$ vault read secret/myapp/config
No value found at secret/myapp/config

$ curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
    https://vault.example.com:8200/v1/secret/myapp/config
{"errors":[]}

What It Means

Vault is telling you that it successfully resolved a mount, was permitted to read, and found nothing stored at the path you asked for. Note what it is not saying: this is not a permission error and not a mount error. Both of those have their own distinct messages. No value found means the request went to a real KV mount and the key genuinely has no data at that location — or, far more often, that you asked for a slightly different path than the one the secret lives at.

The single biggest source of confusion is the difference between KV version 1 and version 2. KV v2 is a versioned store, and its API splits reads, metadata, and deletion into separate path prefixes: data lives under <mount>/data/<path>, version history under <mount>/metadata/<path>, and destruction under <mount>/destroy/<path>. The vault kv CLI commands hide this by injecting data/ for you — which is why the error above echoes secret/data/myapp/config even though you typed secret/myapp/config. Any code that calls the HTTP API directly, or uses vault read instead of vault kv get, must insert that segment itself. Get it wrong in either direction and you get an empty result rather than a helpful error.

Common Causes

  • The mount is KV v2 but the caller used the v1-style path (secret/myapp/config) on the raw API, omitting data/.
  • The mount is KV v1 but the caller inserted data/, creating a path that simply does not exist.
  • The mount path and the secret path were conflated — for example a mount at kv/ but a request to secret/.
  • The secret exists in a different namespace (Vault Enterprise / HCP Vault) than the one the token is scoped to.
  • The latest version was soft-deleted or destroyed, so the key still appears in vault kv list but returns no data.
  • A trailing slash, a typo in the leaf key, or case differences — Vault paths are case-sensitive.
  • The secret was written to a different cluster or a replication secondary that has not caught up.

Diagnostic Commands

First, confirm the mount exists and find out which KV version it is. The -detailed flag surfaces the version in the options column:

vault secrets list -detailed

Look at the Options column for the mount. KV v2 shows map[version:2]; KV v1 shows map[version:1] or an empty map. This one command resolves the majority of these errors.

List what actually exists at the parent path:

vault kv list secret/myapp
vault kv list -mount=secret myapp

Check the version history and deletion state — a key that lists but does not read is almost always soft-deleted:

vault kv metadata get -mount=secret myapp/config

The output shows current_version, plus a per-version table with deletion_time and destroyed fields. A non-empty deletion_time on the current version explains an empty read exactly.

Confirm which namespace your token is operating in:

env | grep VAULT_NAMESPACE
vault token lookup -format=json | jq '.data.policies, .data.meta'

Compare the raw API paths side by side to prove which shape the mount expects:

curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
  https://vault.example.com:8200/v1/secret/data/myapp/config | jq
curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
  https://vault.example.com:8200/v1/secret/myapp/config | jq

Step-by-Step Resolution

  1. Determine the KV version before changing anything else. Everything downstream depends on this:
vault secrets list -detailed | grep -E '^secret/|^kv/'
  1. If the mount is KV v2, use the vault kv commands with -mount= and give the secret path without the mount prefix. This is the unambiguous form and avoids the path-parsing heuristics entirely:
vault kv get -mount=secret myapp/config
vault kv get -mount=secret -field=db_password myapp/config

For direct API calls against a v2 mount, insert data/ after the mount and read the nested .data.data object:

curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
  https://vault.example.com:8200/v1/secret/data/myapp/config | jq '.data.data'
  1. If the mount is KV v1, do not insert data/. vault read and the raw path are correct, and the payload is a flat .data object:
vault read secret/myapp/config
curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
  https://vault.example.com:8200/v1/secret/myapp/config | jq '.data'
  1. Walk the tree if the path itself is in doubt. Listing from the mount root down finds transposed segments and stray prefixes quickly:
vault kv list -mount=secret /
vault kv list -mount=secret myapp

Remember that vault kv list on a v2 mount shows keys that exist in metadata even when their data has been deleted, so a key appearing here does not guarantee a readable value.

  1. Recover a soft-deleted version if metadata shows a deletion_time. Undelete restores the data; a destroyed: true version is gone permanently and must be rewritten:
vault kv metadata get -mount=secret myapp/config
vault kv undelete -mount=secret -versions=3 myapp/config
vault kv get -mount=secret myapp/config
  1. Set the namespace explicitly if you run Vault Enterprise or HCP Vault. A token issued in admin/engineering will not see secrets in admin/platform, and the error is indistinguishable from a missing key:
export VAULT_NAMESPACE=admin/engineering
vault kv get -mount=secret myapp/config

If the same read starts failing with a 403 once you correct the path, the problem has moved from path resolution to policy — see Vault error: “permission denied”, which covers the extra data/ segment that KV v2 policies also require.

For generating KV v2 policy documents and path-correct client snippets from your mount layout, the Vault prompts in the prompt library can produce a reviewed starting point.

Prevention

  • Standardise on vault kv subcommands with an explicit -mount= flag so the data/ segment is never hand-written.
  • Record the KV version alongside each mount in your documentation and Terraform, since v1 and v2 are not interchangeable.
  • Use official client libraries’ KV v2 helpers rather than building raw paths with string concatenation.
  • Set max_versions and a deletion policy on v2 mounts deliberately, so version pruning is expected rather than surprising.
  • Export VAULT_NAMESPACE in shared shell profiles and CI so namespace drift cannot silently change what a path resolves to.
  • Add a startup check in applications that reads a canary key and fails loudly, instead of treating an empty secret as an empty string.
  • permission denied — the path is right but the policy does not grant read on it, including the data/ segment on v2.
  • no handler for route "secrets/myapp/config" — the mount itself does not exist, a different failure from an empty key.
  • missing client token — no authentication was supplied, so path resolution never happened.
  • Version 3 not found for secret/myapp/config — the path is correct but the requested -version was destroyed or never existed.

Frequently Asked Questions

Why does the error echo a path with data/ that I never typed? The vault kv commands automatically insert data/ for KV v2 mounts before sending the request, and the error reflects the real API path. It is a strong hint that you are on a v2 mount.

Why does vault kv list show the key but get returns nothing? On KV v2, listing reads metadata while getting reads data. A soft-deleted version leaves metadata in place, so the key lists but has no readable value. Run vault kv metadata get and undelete the version you need.

Should I use vault read or vault kv get? Prefer vault kv get for any KV mount — it handles both versions and the data/ injection. Reserve vault read for non-KV engines such as databases, PKI, or transit.

Could this be a namespace problem rather than a path problem? Yes, and it looks identical. Confirm VAULT_NAMESPACE and run vault token lookup to see where your token actually lives. If the token turns out to be invalid rather than misplaced, see Vault error: “token expired”.

Free download · 368-page PDF

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?

Free download · 368-page PDF

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.