Errors¶
Plugin failures are typed TOVIO errors, not opaque shell failures. Every error carries a stable
TVO-PLUGIN-* code, and the failure is structured so an agent can branch on the typed status and
the finding codes rather than scraping text (REQ-PLUGIN-076).
The TVO-PLUGIN-* catalog¶
| Code | Meaning | Typical cause | What to do |
|---|---|---|---|
TVO-PLUGIN-001 |
Plugin manifest invalid | Missing required field, bad type/runtime, malformed id, no integrity metadata and no local-dev marker, or a file that is not valid TOML. |
Fix the field the reason names, then re-run tovio plugin validate <path>. install validates before it writes, so nothing was stored and there is nothing to undo. |
TVO-PLUGIN-002 |
Plugin not installed / unsupported source | A command resolved a plugin id against .tovio/plugins/<id>/ and found nothing — or plugin install could not resolve the source (unsupported scheme or URL shape, TLS/connect/read failure, non-success response, or a response over its streaming size limit). |
tovio plugin list to see what is installed. Then install from a local package path, or from an HTTPS URL ending in / or /manifest.toml that serves a sibling plugin.wasm. |
TVO-PLUGIN-003 |
Plugin integrity check failed | Missing artifact, SHA-256 mismatch, malformed or invalid Ed25519 signature, missing publisher DID, untrusted or revoked publisher, or a malformed trust store. | Re-install from a trusted package; tovio plugin trust add did:key:… if you verified the key out of band; rotate to a new key after a revocation; or tovio plugin uninstall <id>. Never treat a mismatch as noise — TOVIO fails closed for a reason. |
TVO-PLUGIN-004 |
Plugin event unsupported | Bound to (or run for) an event the manifest does not declare, an unknown event name, or unbind naming a pair with no binding. |
tovio plugin show <id> lists the events the manifest declares; bind to one of those. |
TVO-PLUGIN-005 |
Plugin capability denied | The manifest ∩ binding intersection withheld a capability the operation needed. | Widen the binding grant — never beyond the manifest request — or narrow what the plugin needs. A plugin can never grant itself more. |
TVO-PLUGIN-006 |
Plugin sandbox failed (exit class 1, 2 or 13) |
The artifact is not a valid WASM module or lacks the WASI entry point, the guest imports a network/filesystem/env host function the sandbox does not provide, there is no runtime artifact, run was called on an unbound plugin, or the binary was built without the sandbox. |
Fix the artifact (valid wasm32-wasi, no forbidden imports), install a package that has one, bind the plugin to the event, or rebuild with --features plugins-wasm. tovio plugin doctor triages the config half. |
TVO-PLUGIN-007 |
Plugin timed out | The plugin exceeded timeout_ms and was terminated — by the instruction (fuel) budget or by the wall-clock deadline. |
Raise timeout_ms in the manifest if the work is legitimately long, or fix a plugin that loops and never terminates. A terminated run has no verdict, so it fails closed. |
TVO-PLUGIN-008 |
Plugin output schema invalid | Absent output, non-JSON output, a result claiming a different plugin id or event, a bad schema version, an empty summary, or an empty finding message. | For plugin authors: emit the current output schema and reproduce with tovio plugin test. For users: file a plugin bug — TOVIO coerces this to error, so it fails closed on a required operation. |
TVO-PLUGIN-009 |
Required plugin failed | An enforcing binding ran its plugin and got fail. This blocks whether or not the binding is required — the gate ran before the operation took effect, so nothing changed. |
Fix what the plugin flagged, then re-run tovio land / tovio commit. The owner override is to drop the local enforcing binding or re-bind it advisory: tovio plugin unbind <id> --event <event>. |
TVO-PLUGIN-010 |
Required plugin unavailable | The required plugin errored, was skipped or reported unsupported, is not installed (a dangling binding), or cannot run because this build has no sandbox. | Make it runnable and passing: re-install a missing plugin, fix one that errors, rebuild with --features plugins-wasm, or (owner) drop / re-bind-advisory the binding. |
TVO-PLUGIN-011 |
Protected plaintext denied | Execution preflight found the input's redaction policy plaintext-allowed while the effective grant lacks read_protected_plaintext. Refused before any guest code ran. |
Run the plugin with metadata-only redaction (the default). Protected plaintext access is a deferred, fully-approved opt-in. |
TVO-PLUGIN-012 |
Plugin network denied | The effective grant asked for network_access. The sandbox exposes no network host functions at all, so it cannot be honored. |
Remove the network capability from the binding grant, or use a plugin that does not need the network. Adding network_access will not turn it on. |
TVO-PLUGIN-013 |
Protected plaintext grant refused (exit class 2) |
tovio plugin bind --grant read_protected_plaintext or tovio policy hook add --grant read_protected_plaintext — that capability needs the full §10 chain, not a flag. |
Drop read_protected_plaintext from the --grant list. Nothing was written; every other capability, and --grant-read-path, is authored normally. |
TVO-PLUGIN-013 |
Post-event plugin failed (exit class 12) |
A required enforcing plugin bound to a post-* or conflict-created event reported a failure after the operation was already durable. |
Address the reported finding as a follow-up change; the operation itself stays. The signed audit chain has already recorded the block. Exit class 12 (POST_EVENT_FAIL). |
TVO-PLUGIN-014 |
Forge enforcing binding refused by org policy (server-side, 422) |
The served organization plugin allow/deny policy does not permit that plugin id (or its publisher) to back an enforcing gate. | A Forge admin has to allow the id in the served plugin-policy document, or the proposal has to use a permitted plugin. A policy that fails to load refuses too, by design — a corrupt policy never degrades to permit-all. |
TVO-PLUGIN-015 |
Landing blocked: no attested passing result (server-side, 422) |
The required plugin:<id> check is absent, not passing, not authored by a policy-approved attester, or stamped with a stale revision. |
Get a passing attested result for the proposal's current revision. An amend invalidates a prior plugin attestation exactly as it invalidates approvals, and a conformant runner re-executes. |
TVO-PLUGIN-016 |
Server-side plugin registration refused (server-side, 422) |
A hosted registration carried unverifiable or local_dev integrity, a sha256 mismatch, an over-cap or non-wasm artifact, or hit an org-policy deny at upload. |
Register a signed package with verifiable integrity, within the size and wasm-shape caps, whose id the org policy permits. |
Two entries share TVO-PLUGIN-013. That is deliberate and documented: TVO-PLUGIN-013 and
TVO-PLUGIN-006 are the two named compatibility exceptions whose stable descriptor is keyed by
(code, exit_class) rather than by the code alone. 013 carries usage (2) and post-event-failure
(12); 006 carries generic (1), usage (2) and permission (13) — the generic one being the
lean build with no sandbox compiled in, and the usage one being a config fault such as run on an
unbound plugin. For those two codes, read the exit class; never infer a numeric exit from the code
alone. Every other TVO-PLUGIN-* code maps to exactly one exit class.
TVO-PLUGIN-013¶
The post-event half of TVO-PLUGIN-013 is different in kind from TVO-PLUGIN-009 /
TVO-PLUGIN-010:
- Those are pre-event blocks — the operation is refused before it takes effect (exit class
13/ PERM). - The post-event
TVO-PLUGIN-013is a diagnostic — the operation (commit, land, …) has already succeeded and is durable. The plugin runs afterward for observability. If a required enforcing binding fails, the CLI returns exit class12(POST_EVENT_FAIL) so CI or orchestration can observe it, but the operation itself is not undone.
See Lifecycle events → Post-event semantics for the full rules.
How errors surface¶
Human output¶
Every enforcing block is a structured explanation, not a stack trace:
✗ Land blocked by required plugin: com.example.license-check
A REQUIRED enforcing `pre-land` plugin blocked the land (sandboxed-lifecycle-plugins.md §14/§57,
REQ-PLUGIN-054/055/065). The operation was gated BEFORE it took effect — nothing changed.
Plugin: com.example.license-check v1.2.0
Binding: com.example.license-check@pre-land (LOCAL, enforcing, required)
Result: fail (enforcing fail)
Why: One dependency violates repository license policy.
[error] Dependency xyz uses a prohibited license. (Cargo.toml)
This was a LOCAL enforcing binding — not a CI-side or Forge-side gate. Override IS possible for the
repo owner (this is a local binding, not org policy).
Fix what the plugin flagged (see the findings above), then re-run `tovio land`
Or inspect the enforcing binding that required it:
tovio plugin bindings
Owner override: drop the local enforcing binding, or re-bind it advisory:
tovio plugin unbind <plugin-id> --event pre-land
[TVO-PLUGIN-009]
For a pre-snapshot gate the title reads Snapshot blocked by required plugin: … and the retry
guidance points at tovio commit.
JSON output¶
--json emits the standard TOVIO error envelope — the same shape every command uses, so an agent
needs no plugin-specific parser:
{
"error": {
"area": "plugin",
"category": "plugin",
"code": "TVO-PLUGIN-009",
"title": "Land blocked by required plugin: com.example.license-check",
"cause": "A REQUIRED enforcing `pre-land` plugin blocked the land …",
"context": {},
"docs": "https://tovio.dev/errors/TVO-PLUGIN-009",
"exit_class": "permission",
"exit_code": 13,
"remediation": [
{ "text": "Fix what the plugin flagged (see the findings above), then re-run `tovio land`" },
{ "text": "Or inspect the enforcing binding that required it", "command": "tovio plugin bindings" }
],
"retryability": "after-user-action"
}
}
Agents branch on code and on exit_class — the latter matters for TVO-PLUGIN-006 and
TVO-PLUGIN-013, whose several meanings are told apart by exit class. The plugin, binding and
finding detail rides in cause; where a code carries a machine surface it appears under context
(the secret-scan gate, TVO-SECRET-001, puts its findings[] and fingerprints[] there).
Fail-closed on protected operations¶
For enforcing bindings on protected operations, the following statuses block:
fail— always.error,skipped,unsupported— when the binding isrequired = true.- Malformed output — treated as
error(TVO-PLUGIN-008).
There is no silent pass. A required plugin that cannot produce a valid pass/warning must stop
the operation.
Where a plugin blockage might be safe to override¶
There is no override flag: tovio land and tovio commit have none. What an owner can do is
change the binding that required the plugin — tovio plugin unbind <id> --event <event>, or re-bind
it advisory. The block itself is already recorded: an enforcing execution writes signed audit
metadata (REQ-PLUGIN-058..060), so the trail exists whether or not you go on to remove the gate.
The one block with a different escape is the default-on secret scanner. Its binding is
synthesized rather than stored, so tovio plugin bindings shows nothing to unbind; the error itself
names the opt-out (tovio config set secrets.scan off), and on a real terminal tovio commit
offers encrypt / block / allow-once instead of hard-blocking. See
Secret scanning.
Rules of thumb:
- Do not work around
TVO-PLUGIN-003. Integrity failures indicate tampering or corruption; the artifact is untrustworthy. - Do not work around
TVO-PLUGIN-011. Protected-content denials are exactly what protected content is for. - Re-running after
TVO-PLUGIN-007(timeout) is often reasonable if the plugin is known-good and the workload was unusually large. If it recurs, fix the plugin or raisetimeout_ms. - Dropping an enforcing binding to get past
TVO-PLUGIN-009deserves a business reason. Removing the gate is a config change, not an audited override — say why in the change that removes it.
Related¶
Last reviewed September 9, 2026
Suggest an improvement to this page Not for security reports — see disclosure