How to read a TOVIO error code
The TVO-AREA-NNN shape, the exit-code classes, and where the remediation lives.
Written By Dustin
Last updated 16 minutes ago
Every error ends with a code shaped TVO-<AREA>-<NNN>.
TVO— fixed prefix.AREA— the subsystem:PERM,KEY,SYNC,TOKEN,LOCK,STORE,MIG,PLUGIN,MCP,CONFLICT, and others.NNN— a stable number. Numbers are never reused; a retired code is tombstoned with a pointer to its replacement.
Because codes are stable, TVO-PERM-001 means the same thing across versions and is worth searching for directly.
Errors are meant to be actionable
Every error has three parts, always in this order:
- What happened — one plain-language line naming the concrete object or path. No code in the first line.
- Why — the cause stated as fact you can verify: which policy, which attribute, which token, which hash. A permission error states what you have alongside what was required, so the gap is self-evident.
- What to do next — concrete steps, most-likely-first, each with a runnable command where one exists.
A permission, key, or crypto error is never a bare "denied". If an error does not tell you what to do next, that is treated as a bug worth reporting.
Exit codes: one class per area
Exit codes are deliberately coarse, so a script can branch on category while the precise code stays in --json.
The mapping is per area, not per code, and a handful of codes are deliberate exceptions — TVO-TOKEN-008 and TVO-TOKEN-011 both exit 11 rather than 13, because what failed is key material. Branch on the code when you need to be exact.
For scripts
Pass --json and branch on error.code, never on message text or on the numeric exit alone:
{ "error": { "code": "...", // the stable code — the primary key "area": "...", // subsystem, derived from code "category": "...", // semantic category, e.g. authorization "exit_class": "...", // symbolic form of exit_code "retryability": "...", // never | after-user-action | transient "title": "...", // the What "cause": "...", // the Why "remediation": [ ... ], // ordered; each has text and an optional command "context": { ... }, // code-specific facts "exit_code": 13, "docs": "..." // optional per-code deep link }}Do not infer retryability from the area or the exit code — read the retryability field, which is the only place that answers it. An older envelope may omit area, category, exit_class, and retryability; a reader should tolerate that and derive them from the code and exit_code pair.
Only title, cause, and remediation[].text are localizable. The code, the context keys, the command strings, and the exit code are the locale-invariant machine surface. A context object never carries a value you are not authorized to read.
Full detail
Most codes have their own page, and the error prints the link on its last line next to the code:
[TVO-PERM-001] https://tovio.dev/errors/TVO-PERM-001Follow it straight from the terminal. The same link is carried in the optional docs field of the --json shape, and is absent for the few codes with no page of their own (the generic TVO-CORE-000 fallback among them). The error reference on the documentation site is the canonical index behind them.
Things that are deliberately not errors
There is no code for "the remote has work you do not have" or "diverged history". A divergent sync reconciles the lane into a two-parent merge-or-conflict commit and reports success. The one guarded case is a push-only sync over a diverged lane, which is refused rather than allowed to clobber the remote tip.