Skip to content

Troubleshooting & FAQ ​

Quick fixes for the things people actually hit. For the long-form CLI manual, tvault help troubleshooting.

Exit codes ​

tvault returns meaningful exit codes, so scripts can branch on them:

CodeMeaning
0Success
1Generic error
3Vault is locked at rest
4Secret or project not found
5Vault not initialized
6Wrong passphrase
7Vault database is in use by another process (e.g. a running tvault run)

"Vault is locked" / "wrong passphrase" ​

The vault is encrypted; reads need it unlocked.

  • Interactively: tvault unlock (or just run a command — you'll be prompted).
  • Non-interactively (CI, scripts, MCP): set TVAULT_PASSPHRASE in the environment, or point TVAULT_PASSPHRASE_FILE (or agent.passphrase_file) at a 0600 env file. See Environment Variables.
  • Exit code 6 means the passphrase was wrong; 3 means it's locked and no passphrase was available.
  • A running agent does not satisfy this for a write. It serves reads only, so set / delete / import / rotate still need the passphrase — see the next section.

"vault is locked" from a tvault nested inside tvault run ​

The same command works on its own but fails with exit code 3 inside tvault run (or MCP vault_run_with_secrets), even with the agent running:

bash
tvault set PROBE x -p demo                                   # works
tvault run --only API_KEY -- tvault set PROBE x -p demo      # "vault is locked"

This is two deliberate boundaries meeting, not a broken socket:

  1. A launched child inherits no TVAULT_* variable. tvault run and MCP exec strip every one of them before starting the child, so the parent's TVAULT_PASSPHRASE never reaches it. That is what keeps a subprocess from receiving the key to the whole vault when you handed it two values. See Security.
  2. The agent serves reads, not unlocks. It caches the key and answers get / getall / getselected — it has no write operation and never hands the key out. So set, delete, import, rotate and friends need the passphrase whether or not an agent is running.

Together: nested reads work (they route through the agent), nested writes do not.

Fixes, best first:

  • Move the write out of tvault run. The wrapper exists to inject values into one process; vault administration belongs beside it, not inside it.

  • Give that one child its own credential, explicitly, if it truly must write:

    bash
    tvault run --only API_KEY -- sh -c 'TVAULT_PASSPHRASE=... tvault set PROBE x -p demo'

    Understand the trade: that child now holds the passphrase to every project and version, which is exactly what --only was narrowing.

tvault shell-init prints nothing / my project didn't load into the shell ​

This is by design, not a bug: shell-init never prompts and never blocks shell startup. If it has nothing to load, it silently exits 0 (a one-line notice goes to stderr unless you passed --quiet).

The usual cause is that no tvault agent is reachable and --allow-unlock wasn't passed (or was passed but no non-interactive source resolves). Fixes:

  • Start or install the agent: tvault agent start & or tvault agent install.
  • Or add --allow-unlock so it can fall back to TVAULT_PASSPHRASE, a passphrase command, or a passphrase file — see Keep the passphrase out of plaintext.
  • Drop --quiet temporarily and open a new shell to see the actual notice on stderr.

A passphrase command works in my shell but not under the agent service ​

tvault agent install's generated launchd/systemd unit starts with a minimal PATH, so agent.passphrase_command: ["op", "read", "..."] can resolve fine interactively and fail under the service. Use the absolute path (command -v op). A password-manager or keychain helper may also need your GUI session already unlocked — at boot, before login, the command can fail, and the agent falls back to failing that one unlock rather than hanging; it should succeed once you're logged in. See Keep the passphrase out of plaintext.

delete / projects delete / restore refused: "safety snapshot ... failed" ​

You've set backup.dir in config.yaml, so tvault delete, tvault projects delete, and tvault restore take a safety snapshot before making any change — and refuse to proceed if that snapshot can't be written. Nothing was deleted or overwritten; fix the underlying problem and retry:

bash
tvault delete API_KEY
# Error: safety snapshot before pre-delete failed (nothing was changed; fix backup.dir or remove it from ~/.tvault/config.yaml): ...

Common causes: backup.dir doesn't exist and its parent isn't writable, the destination disk is full, or (on macOS/BSD) an old snapshot at that path is still marked --immutable and blocking the write. Run tvault doctor to see where backup.dir currently points, fix the directory or free space, or remove backup.dir from config.yaml to go back to unguarded deletes. See Backups & recovery.

"Operation not permitted" deleting a backup snapshot ​

A snapshot taken with --immutable / backup.immutable: true carries the macOS/BSD user-immutable flag (chflags uchg), so rm (even as the file's owner) fails with Operation not permitted. This is by design — it's a guard against an accidental rm -rf on the backup directory, not against you clearing the flag on purpose:

bash
chflags nouchg ~/Backups/tvault/vault-20260923-030000.000.db.gz
rm ~/Backups/tvault/vault-20260923-030000.000.db.gz

tvault backup's own rotation clears the flag on snapshots it prunes automatically — you only need to do this by hand when removing a snapshot yourself, outside of rotation. See Immutability.

"vault not found" / "not initialized" ​

Exit code 5. Create a vault first:

bash
tvault init

By default the vault lives at ~/.tvault/vault.db (override with --vault or TVAULT_DIR). See Configuration.

The MCP server won't connect ​

The MCP server (tvault mcp) speaks JSON-RPC over stdio, so it can never prompt — stdin carries MCP messages. It unlocks in one of two ways: through a running tvault agent (the default, --connect auto), or with a passphrase source it can read non-interactively. It does not hold the vault open; see the next section.

  • "Connection closed" right away → it could not unlock. Either start the agent (tvault agent start), or give the server a passphrase in the host's env: TVAULT_PASSPHRASE, or preferably TVAULT_PASSPHRASE_FILE / TVAULT_PASSPHRASE_COMMAND (a password-manager helper) so the secret is not inline in the host config — see Passphrase sources and MCP Overview → Before you connect.
  • Reads work but vault changes are refused → in agent-backed mode the server cannot write to the database; mutations need a passphrase source even when an agent is running. --connect none (or --no-agent) forces the direct unlock. Note that tools which only read secrets and write a file (vault_export_env, the sealing tools) are not mutations — they follow the policy's access_mode.
  • After changing the passphrase the cached key is stale → restart your MCP/agent sessions so they reconnect with the new one.
  • Tools appear but calls are denied → the Access Policy is gating them (access_mode, allow_exec, project/secret globs). Check ~/.tvault/mcp-policy.yaml; without that file the server starts fail-closed (metadata only, no values, no writes).

"vault is locked by another tvault process" (exit code 7) ​

The on-disk store (bbolt) is single-writer: only one process can hold the database open at a time.

tvault mcp and tvault agent do not block the CLI — they cache only the key and reopen the vault per request, releasing the lock between calls, so set/get/run/import keep working alongside them. A long-running command that holds the database (for example tvault run wrapping a process that never exits) will still block other writers.

If you hit exit code 7 (or doctor reports "in use by another process"), quit the other tvault process that is holding the database and retry. This used to surface as an opaque open bolt db: timeout.

tvault agent says "unix-only" ​

The local agent is Linux/macOS only — on Windows it returns "unsupported platform". Use the direct CLI or the MCP server instead; both work everywhere.

"project has no recipients" ​

vault_export_env_encrypted (and tvault seal with no --recipient/.tvault-recipients) seal to the project's current recipients. If none are set, share the project first:

bash
tvault projects share tvault1…          # CLI

…or use tvault seal --recipient tvault1… / vault_seal_for_recipients with explicit recipients. See Sharing and Committable Secrets.

"identity export refuses to print" ​

tvault identity export prints a private key, so it refuses to write to a non-terminal (to avoid landing in a captured log). Pipe it deliberately with --force:

bash
tvault identity export ci --force | gh secret set TVAULT_IDENTITY_KEY

Rotating the passphrase broke my .env.encrypted ​

tvault key rotate re-wraps the vault keys but invalidates v1 (passphrase-tied) .env.encrypted files. Use the v2, recipient-based format (encrypt-env --recipient / seal), which is KEK-independent and survives rotation. See Committable Secrets.

FAQ ​

Where is my data? One local bbolt database at ~/.tvault/vault.db (0600), in a 0700 directory. Secret payloads and key material are encrypted; names, timestamps, versions, audit entries, and other operational metadata remain readable to someone who can read the file. Identities, optional config, and the MCP policy live beside it. See Configuration.

I forgot my passphrase — can I recover it? No. There is no escrow or recovery key by design (local-first). Keep a backup of the passphrase (e.g. in a password manager). You can still share/recover projects via identities if you set them up beforehand.

Can an AI agent read my secret values? Yes, if its policy permits the explicit vault_get_secret tool; vault_set_secret can also receive a plaintext value from the client. Prefer metadata search plus vault_run_with_secrets when the value does not need to enter the conversation, and remember that subprocess output redaction is only a safety net. See the MCP safety model and Security.

Is it safe to commit .env.encrypted / .tvault-recipients? Yes — .env.encrypted is ciphertext and .tvault-recipients holds only public keys. Never commit ~/.tvault/, *.key identity files, or a plaintext .env.

Does it work on Windows? The CLI and MCP server: yes (amd64/arm64). The unlock-once agent: no (unix only).

How do I back up the vault? tvault backup [path] writes a consistent snapshot (a bbolt read transaction, never a raw file copy) without decrypting any records. Without a path, --dir/backup.dir gives you rotated, compressed, timestamped snapshots with pruning. The matching passphrase restores the complete owner view; a pre-provisioned recipient identity can read only projects shared to it. Operational metadata remains readable, so treat the backup as sensitive. See Backups & recovery.

See also ​

Released under the MIT License.