On this page

API

Errors

Every API error is application/problem+json with a stable code. The full catalogue of 43 codes with status, meaning, the fix and an example response for each.

Every non-2xx response is application/problem+json (RFC 9457). Branch on code, show detail to people, and quote request_id when you ask for help.

http
HTTP/2 404
content-type: application/problem+json; charset=utf-8
x-request-id: req_yzyjoipk6hhhoco2

{
  "type": "https://reuseforge.com/docs/api/errors/not_found",
  "title": "Not found",
  "status": 404,
  "detail": "No item \"nope/nope\".",
  "instance": "/api/v1/items/nope/nope",
  "code": "not_found",
  "request_id": "req_yzyjoipk6hhhoco2"
}
MemberMeaning
typeA URL on this site that documents the code. It resolves to the page for that code in the catalogue.
titleShort and stable for a code. Safe to match on, but code is the contract.
statusThe HTTP status, repeated.
detailA sentence for people. It can change; never parse it.
instanceThe request path.
codeThe stable machine-readable code from the table below. New codes can be added in a minor release, so keep a default branch.
request_idThe same value as the X-Request-Id response header.
other membersDefined per code: errors (field problems), required_scopes, limit_cents, spent_cents, retry_after, state, current_etag, order_hint.

Field problems

validation_failed (422) and invalid_parameter / invalid_request (400) carry an errors array. Each entry has a JSON pointer into the request, a short code and a message:

json
{
  "type": "https://reuseforge.com/docs/api/errors/invalid_parameter",
  "title": "Invalid parameter",
  "status": 400,
  "detail": "One or more query parameters are invalid. See `errors`.",
  "instance": "/api/v1/items",
  "code": "invalid_parameter",
  "request_id": "req_ztx7yicxbbkthgvp",
  "errors": [{ "pointer": "#/limit", "code": "out_of_range", "message": "Must be at most 100." }]
}

Show the message next to the field the pointer names. Unknown fields in a request body are rejected, while unknown fields in a response must be ignored.

What to retry

SituationRetry?
Network failure, timeoutYes, with backoff. Safe for reads, and for writes that carry an Idempotency-Key.
429 rate_limitedYes, after Retry-After seconds. See rate limits.
502, 503, 504Yes, with backoff (503 unavailable and upstream_error carry retry_after).
500 internalOnly for idempotent calls (GET, PUT, DELETE, or a POST with an Idempotency-Key).
409 idempotency_in_progressYes, once retry_after has passed. The first call is still running.
Any other 4xxNo. Change the request.

The Python and JavaScript SDKs implement exactly this table, and map each class of error to a typed exception.

Handling errors

Python

python
import reuseforge
from reuseforge import ReuseForgeError, PaymentRequiredError, RateLimitError

client = reuseforge.Client()
try:
    client.install("acme/paid-tool", target="claude-code", dest=".")
except PaymentRequiredError as e:
    print("buy first:", e.order_hint)           # the create_order request that buys it
except RateLimitError as e:
    print("slow down, retry in", e.retry_after)
except ReuseForgeError as e:
    print(e.status, e.code, e.detail, e.request_id)

JavaScript

javascript
import { ReuseForge, PaymentRequiredError, RateLimitError, ReuseForgeError } from '@reuseforge/sdk';

const client = new ReuseForge();
try {
  await client.getInstallDescriptor('acme/paid-tool');
} catch (e) {
  if (e instanceof PaymentRequiredError) console.log('buy first:', e.orderHint);
  else if (e instanceof RateLimitError) console.log('retry in', e.retryAfter);
  else if (e instanceof ReuseForgeError) console.log(e.status, e.code, e.detail, e.requestId);
  else throw e;
}

curl

bash
# -f makes curl fail on 4xx/5xx; the problem document is still printed with --fail-with-body
curl --fail-with-body -sS https://reuseforge.com/api/v1/items/acme/missing || true

CLI

bash
rf items get acme/missing --json     # exit code 4; stdout carries the problem plus exit_code
echo $?

The CLI maps errors to exit codes (3 authentication, 4 not found, 5 conflict, 6 invalid input, 7 payment, 8 rate limited, 9 network or server, 10 integrity, 11 confirmation); see the CLI reference.

Catalogue

Each code has its own page with a typical response and the fix. The type member of a problem links straight there.

Error codes
CodeHTTPMeaningExtra members
invalid_request400The request is malformed in a way that fits no narrower code.errors
invalid_json400The body is not a JSON object.none
invalid_parameter400A query or path parameter is unknown or has the wrong form.errors
invalid_cursor400The pagination cursor expired or was altered.none
validation_failed422The body is valid JSON but some fields are not valid.errors
unsupported_media_type415The request body is not application/json.none
payload_too_large413The body, a file or a version is over the published limits.none
unauthorized401The operation needs a token and the request had none.none
invalid_token401The token is malformed, unknown or revoked.none
token_expired401The token is past its expiry date.none
insufficient_scope403The token lacks a scope the operation needs.required_scopes
forbidden403You are signed in but not allowed to do this.none
account_suspended403The account is suspended.none
email_unverified403Paid listings need a verified email address.none
spend_limit_exceeded403The token's lifetime spend limit would be exceeded.limit_cents, spent_cents
purchase_required403Reviewing or accessing this needs a verified purchase.none
payment_required402The content is paid and you have no entitlement.order_hint
payment_invalid422The submitted transaction does not match the order.none
rail_unsupported422The rail is disabled or not valid for these items.none
not_found404No such resource, or it is not visible to you.none
method_not_allowed405The path exists but not for this HTTP method.none
gone410The resource was removed for good.none
plan_expired410Plans can be fetched for 24 hours only.none
conflict409The request conflicts with the current state of the resource.none
already_exists409A duplicate slug, version, review or webhook.none
invalid_state409The lifecycle does not allow this now.state
idempotency_key_required400A call that moves money was sent without an Idempotency-Key.none
idempotency_key_reuse422The same key was used for a different request.none
idempotency_in_progress409The first request with this key is still running.retry_after
precondition_failed412If-Match is stale: the resource changed since you read it.current_etag
precondition_required428If-Match is required and was not sent.none
quota_exceeded403An account limit was reached (50 tokens, 20 webhook endpoints, item count). Publishing a version that does not fit the owning account's storage quota (20 MB unverified, 200 MB verified email, 1 GB verified publisher) answers the same code with status 413.none
version_quarantined403The security scan or a moderator blocked this version, so its files, install descriptor and archive are not served.none
review_removed403A moderator removed your review of this item. It stays as a tombstone, so it cannot be deleted, edited or posted again.none
rate_limited429A rate limit tier is used up.retry_after
webhook_url_forbidden422The URL fails the safety rules for webhook targets.none
invalid_signature422A ledger event's signature or hash is invalid.none
integrity_mismatch422A content_hash or file sha256 differs from the server's computation.none
upstream_error502A connector or a chain RPC failed.retry_after
upstream_timeout504An upstream source was too slow.none
not_implemented501The operation is in the contract but this deployment does not provide it yet.none
internal500Our fault.none
unavailable503Maintenance, or a dependency is down.retry_after

Last updated: