verb failure recovery
You ran a verb and got failed (or --apply errored before
emission). This runbook is the operator-shaped recovery playbook,
mapped to the errors[].code returned in the output envelope.
The fleet-shaped version of this catalogue is at
/integrations/example-failure-modes/.
That page is for fleet authors writing automated retry logic; this
page is for the human at the terminal.
Triage flow
Section titled “Triage flow”verb returned failed? │ ├── error code in output envelope? │ │ │ ├── AUTH_* → set credentials (see /runbooks/auth-setup/) │ ├── REPO_* → registry mismatch — fix registry.yaml │ ├── FIELD_* → input JSON malformed — fix and retry │ ├── FLEETS_* → fleet not allowed — see below │ ├── PROFILE_* → wrong verb for repo profile — switch verb │ ├── DIAGNOSIS_* → propose_fix needs a fresh diagnose │ └── (other) → see per-code section below │ └── no error code, just exit code 2? → unhandled exception. Report as bug with the JSON output.Per-code recovery
Section titled “Per-code recovery”AUTH_MISSING
Section titled “AUTH_MISSING”Cause: --apply invoked without credentials.
Fix:
export PETROVA_GITHUB_TOKEN="$(op read 'op://PETROVA/PETROVA_GITHUB_TOKEN/credential')"# or set the App env tripleRe-run.
REPO_NOT_IN_REGISTRY
Section titled “REPO_NOT_IN_REGISTRY”Cause: target slug not in registry.yaml.
Fix: Either you typoed the slug (rerun with correct one) or the
repo isn’t governed yet. For onboarding, see
/runbooks/onboard-repo/.
REPO_LOCAL_PATH_MISSING
Section titled “REPO_LOCAL_PATH_MISSING”Cause: read verbs (diagnose, validate) couldn’t find the
local clone at $PETROVA_WORKSPACE/<slug>.
Fix:
cd $PETROVA_WORKSPACEgit clone https://github.com/<owner>/<repo>.git <slug>Or set PETROVA_WORKSPACE to the directory where you cloned it.
FIELD_PATTERN, FIELD_REQUIRED, FIELD_ENUM
Section titled “FIELD_PATTERN, FIELD_REQUIRED, FIELD_ENUM”Cause: input JSON fails schema validation.
Fix: the error message names the offending field path
(e.g. /params/slug). Look at the verb’s schema in
spec/verbs/<verb>.schema.json to see the expected shape, fix
the JSON, retry. The skill recipe (skills/petrova-act/verbs/<verb>.md)
has worked examples.
FLEETS_ALLOWED
Section titled “FLEETS_ALLOWED”Cause: invoked verb with --actor fleet:<id> but <id> not in
the target repo’s fleets_allowed list.
Fix: Either:
- (a) Run as a human (drop
--actoror usehuman:<email>). - (b) Open a
request_reviewPR againstpetrova-hq/registry.yamladding the fleet to the relevant repo’sfleets_allowed. Wait for merge, then retry.
# Composing the registry edit:cd ~/code/workspace/petrova-hq$EDITOR registry.yaml # add fleet ID to fleets_allowed for target repo# Then propose via verb (yes, you can use the verb to edit the verb's gate):petrova request_review petrova-hq --input /tmp/registry-edit.jsonPROFILE_PERMITS_AUTOMERGE
Section titled “PROFILE_PERMITS_AUTOMERGE”Cause: request_merge_when_green against a strict-profile
repo (or standard without explicit fleet allow).
Fix: switch to request_review instead. Same input minus
merge_method. Human approves the PR.
DEFERRED_HAS_TARGET
Section titled “DEFERRED_HAS_TARGET”Cause: close_phase has a friction item with
classification: deferred but no deferred_to_milestone.
Fix: add deferred_to_milestone: M<phase>.<n> referencing a
later phase, retry.
HUMAN_COUNTERSIGN_PRESENT
Section titled “HUMAN_COUNTERSIGN_PRESENT”Cause: close_phase invoked without sign_off.human populated.
Fix: the human countersigning this close needs to add their identity. Edit input JSON:
"sign_off": { "human": "your-name your@email 2026-04-29" }DIAGNOSIS_EXISTS / DIAGNOSIS_REPO_MATCH
Section titled “DIAGNOSIS_EXISTS / DIAGNOSIS_REPO_MATCH”Cause: propose_fix references a diagnosis ID that’s missing
from the local cache, expired (> 24h old), or was for a different repo.
Fix:
petrova diagnose <slug> --json | jq -r '.result.diagnosis_id'# Use this fresh ID in /tmp/fix.json, retry propose_fix.NO_PRIVILEGED_PATHS
Section titled “NO_PRIVILEGED_PATHS”Cause: input includes a path matching the privileged-path
denylist (.github/workflows/, *.env, secrets/,
deploy/credentials/).
Fix: don’t retry as the same verb. Privileged path edits are operator-only. Make the change manually via direct PR (with human review), separate from the verb pipeline.
BASE_BRANCH_MISSING
Section titled “BASE_BRANCH_MISSING”Cause: target repo’s default_branch (per registry.yaml)
doesn’t exist on GitHub.
Fix: registry data drift. Update the registry entry’s
default_branch field to match reality (typically renamed
master → main).
FILE_ALREADY_EXISTS
Section titled “FILE_ALREADY_EXISTS”Cause: --apply after a previous --apply partially succeeded
(branch created, some files committed, then died). The retry tries
to create a file that already exists on the branch.
Fix:
- Easy path: delete the partial branch on GitHub, retry.
- Surgical path: change the verb’s input slightly (e.g. different decision slug), which produces a new idempotency key and a new branch.
422 Unprocessable Entity (concurrent edit)
Section titled “422 Unprocessable Entity (concurrent edit)”Cause: between dry-run and apply, the default branch’s SHA moved (someone merged something).
Fix: simple retry — the emitter fetches a fresh SHA on each apply attempt.
When to escalate
Section titled “When to escalate”If a verb fails with an error code not in this table, or with no error code (just exit 2), capture:
petrova <verb> <repo> --input <input> --apply --json > /tmp/petrova-error.jsonOpen a finding doc:
docs/findings/YYYYMMDD-HHMM-petrova-verb-failure-<slug>.mdInclude the JSON output, the input file contents, and what you
expected. Either fix it yourself (verb implementations live at
cli/src/verbs/) or surface to the operator.
See also
Section titled “See also”- Failure modes catalogue — the fleet-shaped version with auto-retry guidance.
- Auth setup — for
AUTH_*codes. - Onboard a repo — for
REPO_NOT_IN_REGISTRY.