Docs/OBEP Error Taxonomy raw .md

OBEP Error Taxonomy

Stable error codes carried on status messages (phase: "error", code). The canonical source is ERROR_CODES in @obep/protocol. Consumers MUST tolerate unknown codes (forward-compatible).

Code Meaning Typical cause
no_binding No (tenantId, userId) binding to route to. User never paired, disconnected, or the binding token expired (≥30d idle), or no extension connected. A transient reconnect self-heals via token replay and does not surface this — see PAIRING_LIFECYCLE.md.
permission_denied Action/credential/capture outside the errand boundary. Action not in allowedActions; credentialKey not allowed.
element_not_found Referenced element/selector absent. Page changed; selector stale.
navigation_blocked Domain not allowed, or a blocked sensitive surface. Target outside allowedDomains; unacknowledged sensitive surface.
credential_not_found Vault locked or no entry for the key. Vault not unlocked; key never stored.
timeout Operation exceeded its budget. Slow page load / wait.
bad_message Malformed/non-conformant wire message. Invalid JSON; unknown shape.
playbook_invalid Signature/hash verification failed or tenant mismatch. Tampered errand; wrong key; cross-tenant errand.
consent_required Unknown/widened errand needs fresh consent (TOFU). First use, or scope widened vs the approved version.
halted Deterministic step couldn't proceed and fallback: "halt". High-assurance flow chose not to improvise.
unauthorized Bad/revoked API key, or unverifiable task token. Wrong API key; forged/expired task token.
rate_limited Tenant exceeded its rate limit. Too many task starts in the window.
payment_required No free quota or credit balance remaining. Tenant out of quota/credit; top up.
pairing_failed Invalid/expired/used pairing material. Replayed pairing token; bad assertion.
internal Unexpected relay/extension error. Bug; peer disconnected mid-task.

"Can't reach the user" — four distinct failures. no_binding (not paired / token expired) vs credential_not_found (paired, but not logged into the target site) vs permission_denied (action/credential/capture outside the fence) vs pairing_failed (bad pairing material during connect). PAIRING_LIFECYCLE.md walks through telling them apart.

On a terminal error status, the message also carries a run trace (trace, failedStep, finalUrl) so you can see exactly which step failed without reproducing the run — and the SDK rejects with a RunError exposing those fields. See INTEGRATION.md.