## TL;DR

Writes need create or update capability on the path, separate from read. Find the policy gap the same way as for reads, add the missing capability, and retry the write.

## Error

```text
"vault write failed: permission denied"
```

## Steps

1. Confirm the token is valid with `vault token lookup`. Expected: token metadata.
2. Read the token's policies and check the target path for create or update capability (kv-v2 writes go to the `data` path). Expected: the missing capability identified.
3. Note that updating an existing key needs update while creating a new one needs create; grant both if the code does either. Expected: no second round-trip for the other capability.
4. Update the policy and retry the write immediately; policy changes apply at once. Expected: the write succeeds.
5. If the write is from an app, confirm the app re-reads after the policy change rather than caching the denial. Expected: the app proceeds.

## When to use

- `vault kv put` or API writes return 403.
- Setting up rotation jobs or app secret writers.

## When not to use

- Read denials (check read capability instead).
- Auth failures (token invalid).

## Tool compatibility

- Vault kv-v2; HCL policies.

## Variant phrasings

### vault 403 on kv put

Same cause.

### vault write permission denied for approle

The approle's policies need the capability, not the login.

## Why it happens

Vault splits read, create, update, and delete into separate capabilities, and kv-v2's `data` path segment trips up policies written for v1 paths.

## Edge cases

- Check-and-set writes (CAS) need the current version; a 403 can mask a version mismatch, so verify the capability first.
- Dynamic secret roles have their own permission model separate from kv policies.
- Some paths are blocked by `deny` rules; allows elsewhere do not override.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_fVwA95LUus9vyiUCFMiv9A
