Troubleshooting
Quick summary
Start with the CLI exit code, then inspect the printed status or --json output. NOT_AVAILABLE means an endpoint is missing—not a successful integration.
For protection failures, check the target file, approval, plan hash, and generated evidence before retrying.
Exit codes first
Every CLI outcome maps to one of four exit codes — start diagnosis there:
| Exit | Name | Typical causes |
|---|---|---|
0 | ok | Stage completed. NOT_AVAILABLE/NOT_CONFIGURED statuses also exit 0 — they are honest answers, not failures. |
1 | fail | Stage ran and failed: doctor check FAIL, equivalence FAIL_ADOPTION, invalid evidence record, bad login, unauthenticated auth status, invalid license key. |
2 | needs-approval | Missing required input (protect.target unset, no positional arg), invalid spec, plan/spec/target sha drift on apply, approval required. |
3 | refused | Fail-closed refusal: apply refused by the pipeline (e.g. unapproved AUTO decision), or 401/403 from an auth-required command → "run yp auth login". |
With --json, the object carries status, error, and command-specific fields — yp-mcp surfaces these verbatim.
Common failures
protect plan refuses: no protect target
init never guesses a paid boundary. Set it:
yp init --force --target src/paid.mjs
# or edit devpay.json: "protect": { "target": "src/paid.mjs" }2
Rust projects: the analyzer reads js/wasm modules only — point protect.target at the .mjs paid-logic wrapper, not Cargo sources.
apply exits 2 — sha drift
The plan is bound to the exact spec/target/driver bytes (plan.spec_sha256, plan.target_sha256, plan.driver_sha256). If you edited any of them after planning, the approval is stale: re-run yp protect plan, review again, then apply.
apply exits 3 — refused
An AUTO decision under an unapproved/draft spec is refused even with --approve (handoffs only). Promote the spec: review .devpay/spec.draft.json, resolve every REQUIRES_APPROVAL marker, save as the approved spec path (protect.spec, default .devpay/spec.json) with draft:false, re-plan, re-apply.
verify exits 2 — nothing applied
Verify attests applied work. A plan.json alone is planned, not applied — run yp protect apply first (.devpay/apply-report.json must exist).
auth status / platform commands exit 3
No stored credential or the backend rejected it. Run:
yp auth login --api-base <url>
yp auth status2
If login succeeds on Axum (be/) the stored type is dev-user — X-Dev-User only authenticates on dev-auth deployments; a production backend answers 401 and the CLI reports it.
integration check prints NOT_AVAILABLE (exit 0)
The route was not routed on the backend the CLI reached (detected via the Worker request_id 404 fingerprint). This is an honest degrade — verify you are pointing at the intended backend (--api-base) and that the deployment includes the d3 integration-parity routes (be-cloudflare/src/lib.rs /api/v1/projects/:id/integration arm).
license status shows probes NOT_AVAILABLE
bindings/usage detail probes exist only on be-cloudflare; on the Axum backend they always report NOT_AVAILABLE. The base list works on both.
license status <key> "not found"
License keys are not exposed by the seller list on the Worker backend — a key argument falls back to the public verify endpoint (source:"public-verify" in JSON). A NOT_FOUND verdict there means the key is not in the seller list and does not verify publicly — it may belong to another seller.
doctor FAILs
doctor prints each check (node version, toolkit, SDK, config, API, git) with ok/FAIL — fix only the failing items; a FAIL anywhere exits 1.
Getting more signal
yp <cmd> --json # structured status + error fields
yp <cmd> --help # per-command contract
cat .devpay/state.json # plan/spec/target shas the apply gate binds to
cat .devpay/apply-report.json .devpay/verify-report.json2
3
4