Skip to content

fix(errors): a key that hit its credit cap was told the account is out of credits and to buy a top-up - #24

Merged
AnderRV merged 2 commits into
mainfrom
fix/key-cap-402-not-out-of-credits
Oct 2, 2026
Merged

AnderRV merged 2 commits into
mainfrom
fix/key-cap-402-not-out-of-credits

Conversation

@AnderRV

@AnderRV AnderRV commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Why

Zenrows is adding per-API-key credit caps. A request from a key that reached its cap gets a 402: AUTH014 from Fetch, Extract and Browser, and api_key_cap_reached from the Batch API. The CLI treated every 402 as "account out of credits" and told the user to buy a credit pack or upgrade. The account still has credits, so that advice is wrong.

A Batch run the cap stops part-way ends failed with failure_reason: api_key_cap_reached. The CLI printed that with a green check, exited 0, said ok: true, and dropped the reason.

What

  • New error KEY_CREDIT_CAP_REACHED for those 402s in http.ts (scrape/extract), batch-api.ts and browser-api.ts. It passes the API's detail through, which names the cap and its reset date. The next action is to wait for the reset or raise/remove the cap at https://app.zenrows.com/settings/api-keys. Other 402s are unchanged.
  • zenrows usage prints one line per cap on the calling key, for example This key: daily cap 200, 200 used, 0 left, resets 2026-10-03T00:00:00Z. It prints nothing for an uncapped key. --json already passes api_key through.
  • batch status, batch wait and batch create --wait (also cancel/retry-failed, which share the printer):
    • print failure_reason and failure_detail, and include them in --json;
    • a run that ended failed exits 1 with ok: false and an error. api_key_cap_reached gets the KEY_CREDIT_CAP_REACHED guidance (cause names the job, not a 402, since the status call itself succeeded). Any other reason gets BATCH_FAILED with the reason in the cause and results --status failed / retry-failed as next steps;
    • completed stays exit 0 / ok: true, even with failed tasks: per-task failures are results, not a failed run (unchanged);
    • stopped and deleted stay exit 0 / ok: true but print as a warning, not a check. They come from someone cancelling or removing the run, and batch cancel returning non-zero on success would be wrong;
    • the run artifact written by create records status: "error" and the error for a failed run.
  • JobRun types failure_reason / failure_detail.
  • zrErrorProblemDetail moved out from between zrErrorDetail and its JSDoc.
  • Skills: trace-debug maps KEY_CREDIT_CAP_REACHED, POLICY_MAX_CREDITS_EXCEEDED (out of credits) and BATCH_FAILED to an action; batch-jobs documents the terminal states, the exit codes and what to do on api_key_cap_reached.

Verification

  • npm run typecheck: clean. npm test: 206/206.
  • The new batch tests fail without the batch.ts change (4 of them, 201/205), so they catch a regression. The 402 tests from the first commit fail with cap detection disabled.

Against prod (api.zenrows.com, async.api.zenrows.com), built from this branch, isolated HOME:

Command Key Result Exit
fetch https://example.com (human, --json) capped (daily, exhausted) KEY_CREDIT_CAP_REACHED, cause carries the API's AUTH014 detail with reset date, ok:false 1
extract https://example.com capped KEY_CREDIT_CAP_REACHED 1
browser open https://example.com (human, --json) capped KEY_CREDIT_CAP_REACHED on POST /browser/sessions 1
fetch / extract --autoparse / browser run (1 step) uncapped 200, 1 credit; session closed 0
usage (human, --json) uncapped no cap line; api_key.caps: [] 0
usage daily-capped This key: daily cap 200, 200 used, 0 left, resets 2026-10-03T00:00:00Z 0
usage weekly + monthly capped two cap lines, --json shows both 0
batch create one.jsonl (human, --json) capped KEY_CREDIT_CAP_REACHED on POST /jobs 1
batch status / batch wait on a run the weekly cap stopped (human, --json) weekly-capped ✗ status: failed, 45/80 completed, failure_reason: api_key_cap_reached, failure_detail printed, ok:false, error.code: KEY_CREDIT_CAP_REACHED 1 (was 0)
batch create one.jsonl --wait, then --json batch status uncapped ✓ status: completed, 1/1, ok:true 0

Not changed here, seen while testing: extract on a domain Extract has not prepared (REQS007, HTTP 403) surfaces as FETCH_FAILED and suggests --manual --js-render --premium-proxy, the most expensive retry, which cannot help. Worth its own fix.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Lr2QdqhUNrX6q4DRLGeTMY

…t of credits and to buy a top-up

AUTH014 (Fetch, Extract, Browser) and Batch api_key_cap_reached now map to
KEY_CREDIT_CAP_REACHED: other keys still work, wait for the reset or raise the
cap. `zenrows usage` prints the calling key's caps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lr2QdqhUNrX6q4DRLGeTMY
@AnderRV AnderRV self-assigned this Oct 2, 2026
…, so report it as failed with its reason

status, wait and create --wait now print latest_run.failure_reason and
failure_detail (human and --json) and exit 1 with ok:false when the run
ended failed. api_key_cap_reached reuses the KEY_CREDIT_CAP_REACHED
guidance; other failures map to BATCH_FAILED. stopped/deleted stay exit 0
but print as a warning. Also moves zrErrorProblemDetail out from between
zrErrorDetail and its JSDoc, and teaches trace-debug and batch-jobs the
cap, out-of-credits and failed-run codes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lr2QdqhUNrX6q4DRLGeTMY
@AnderRV
AnderRV merged commit fd19a82 into main Oct 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant