Skip to content

Troubleshooting

The failures people actually hit, with the fastest path out of each. If your problem isn’t here, run ov status --explain first — it diagnoses most context problems and prints the fix inline.


Symptom: every MCP tool call from Claude Code (or Cursor / Windsurf) fails with a locked-vault error. There are two distinct failure signatures, and they have different fixes.

The MCP bridge (ov mcp serve) never holds your decryption key — the ov agent daemon does. Which error you see depends on whether the bridge found a running agent when it started.

Signature A — agent running, session locked or expired

Section titled “Signature A — agent running, session locked or expired”

The agent daemon is up, but its unlocked session has ended. Every tool returns a JSON error whose stable signature is:

"code":"SESSION_LOCKED"

The response also carries an action field — a static remediation string telling the AI agent to have you restart the vault agent and reconnect the MCP client. It is deliberately identical no matter when the lock fired, with no timestamps, TTLs, or counters that could act as a timing oracle. Its exact wording may change between releases: match on code, not on action.

Fix: the expired agent process stays alive (expiry only zeroes the key in memory) and still holds the agent lock, so a bare ov agent start fails with another ov agent is already running. The working sequence:

Terminal window
ov agent stop
ov agent start # prompts for your master password; runs in the foreground — keep this terminal open

Then restart (or reconnect) your MCP client. A fresh interactively-started agent mints a new ephemeral socket key, and a bridge that’s already running only reads that key once at startup — it won’t pick up the new one on its own.

Signature B — agent wasn’t running when the bridge started

Section titled “Signature B — agent wasn’t running when the bridge started”

If no agent is running when your MCP client launches ov mcp serve, the bridge starts in degraded mode and every tool returns a plain-text error instead — never SESSION_LOCKED:

ov agent is not running — run 'ov agent start' in a terminal to unlock your vault

Fix: run ov agent start in a terminal (foreground — keep it open), then restart your MCP client. A degraded bridge never re-dials the agent; only a fresh ov mcp serve will connect.

Check what the agent thinks is going on:

Terminal window
ov agent status

Sessions expire by design. The agent locks itself after the session TTL (OV_SESSION_TTL, default 1 hour, max 24 hours) or the idle/max-lifetime timers fire — whichever comes first. If you hit Signature A mid-afternoon after unlocking in the morning, that’s the TTL, not a bug. Restart the session as above, or raise OV_SESSION_TTL in the agent’s environment.

Headless / servers / CI (CLI path only): for ov run on machines with no terminal to type a password into, use a machine key:

Terminal window
# once, interactively, as a human:
ov auth derive-machine-key --out /etc/ov/machine.kek
chmod 600 /etc/ov/machine.kek
# then the agent can unlock without a prompt:
ov agent start --machine-key /etc/ov/machine.kek

Note: the MCP bridge cannot authenticate to a machine-key agent today — a machine-key agent derives its socket key from the KEK and writes no socket-key file, and the bridge only authenticates via the ephemeral key file an interactively-started agent writes. Machine-key mode serves ov run --machine-key and headless CLI use; MCP sessions need an interactively unlocked agent.

On Linux servers, ov agent install --machine-key /etc/ov/machine.kek --app <slug> --env <slug> --enable sets up a systemd unit so the agent survives reboots (--app / --env are required — they’re routing flags baked into the unit’s ExecStart, not key-scoping) — see ov agent. A machine key is equivalent in decryption capability to your master password; treat the file accordingly.


Symptom: ov secret set / ov run / MCP tools fail with a 404-style “app not found” or “environment not found” error, or ov status prints Env OK: no.

First move — always:

Terminal window
ov status --explain

This prints the full resolution trace (which .ov.yaml, config default, or fallback supplied your app/env), preflights the resolved app and env against the server, and prints an actionable Fix: line for every issue it finds. Add --json for scripts.

The common causes it catches:

  • Wrong directory → wrong .ov.yaml → wrong app. You’re running from a directory whose nearest .ov.yaml points at a different project. See .ov.yaml not resolving below.
  • App exists, environment doesn’t. A fresh app created without --with-env has no environments. Fix: ov env create production --app <slug>, or pick an existing one via ov env list --app <slug>.
  • Fell through to hard defaults. No flags, no .ov.yaml, no config default — the CLI used the built-in default app / production env, which may not exist on your account. Fix: cd into your project, or ov app use <slug>, or create a project config with ov init.
  • Legacy .ov.yaml (no app_id). The MCP bridge refuses v1 files outright; the CLI warns and continues. Fix: run ov app pin in the project (no arguments — it reads the slug from the file’s app: field and writes the UUID in place). See Upgrading.
  • Slug renamed or app deleted. ov app list to see what actually exists; then ov app use / ov app pin to repoint.

The Windows-native CLI works today (ov auth, ov secret, ov run, ov scan), but ov agent and ov mcp serve are Linux/macOS only for now — native Windows MCP support is in development (OV-59).

Interim fix: WSL2.

  1. wsl --install (one-time)
  2. Inside WSL2: curl -fsSL https://get.opaquevault.com | sh
  3. Run ov auth login and ov agent start inside WSL2
  4. Point your MCP client at the WSL2-hosted ov binary — Claude Code on Windows can connect to WSL2 MCP servers via localhost

Full details: Windows MCP support (interim: WSL2) in the installation guide.


Symptom: commands target an app or env you didn’t expect, or ov status shows Source: .ov.yaml (/some/path) for a file you forgot existed.

The rule: closest file wins. Every CLI entry point (and the MCP bridge) walks up the directory tree from your current working directory and uses the first .ov.yaml it finds. Nested project trees (monorepos with per-package configs) can carry a .ov.yaml at each level — the one closest to your working directory is the one in effect. The CLI’s walk stops at your home directory; the MCP bridge’s walk stops at the project’s git root, so it never reads a .ov.yaml from outside the repository it was started in.

.ov.yaml sits second in the fixed resolution chain:

  1. Explicit --app / --env flags — always win
  2. Nearest .ov.yaml from the walk-up
  3. Config defaults from ov app use / ov env use
  4. Hard defaults (default app, production env)

Diagnose:

Terminal window
ov status # shows the winning source + the absolute path of the .ov.yaml used
ov status --explain # full per-tier trace: which rungs matched, skipped, or warned

Fixes:

  • A stray .ov.yaml up the tree is hijacking your context → edit/remove it, or pass --app / --env explicitly.
  • The file is legacy v1 (no app_id) and the MCP bridge refuses it → run ov app pin (no arguments) in the project to upgrade it. Note that ov app use does not touch .ov.yaml — it only sets your global config default.
  • The file is corrupt → the CLI prints a warning to stderr and falls through to config defaults; fix the YAML and re-run.

ov run also prints a one-line context summary to stderr before every subprocess (ov run: using app=… env=… (.ov.yaml at …)) so a wrong context is visible before it bites.


  • Verify ov is on the PATH of the process launching the client: which ov
  • Check the MCP config file path and JSON syntax (Claude Code, Cursor, Windsurf)
  • Restart the client completely (quit and reopen)
  • Watch the bridge’s stderr on startup: it logs the agent connection (Connected to ov agent …) or the degraded-mode warning (Run 'ov agent start' in a terminal to unlock your vault)

  • ov status — the one-shot “where am I?” check
  • ov agent — daemon reference, systemd setup
  • Machine keys — non-interactive unlock, full security properties
  • Upgrading — breaking changes by version