Errors
RFC 7807 problem+json responses, the stable type taxonomy, and the patterns clients should rely on.
CiteFoundry returns RFC 7807 application/problem+json for every
non-2xx response. The body has a fixed shape so clients can switch on
a stable identifier rather than parsing free-form text:
{ "type": "https://citefoundry.com/problems/unauthorized", "title": "Unauthorized", "status": 401, "detail": "The provided token has expired. Mint a new one and retry.", "instance": "/v1/projects/proj_01J.../runs"}Fields
| Field | Purpose | Treat as stable? |
|---|---|---|
type | URI identifying the problem class. Switch on this, not on detail. | Yes |
title | Short human-readable summary. | Stable text, suitable for headings. |
status | HTTP status code, mirrored from the response. | Yes |
detail | Free-form description for humans. | No — wording may change. |
instance | Request path. | Yes — useful for logs. |
Some problem types add domain-specific fields (e.g. quotaLimit,
retryAfter). Treat unknown fields as additive.
Common problem types
https://citefoundry.com/problems/unauthorized 401 — invalid/expired tokenhttps://citefoundry.com/problems/forbidden 403 — no access to resourcehttps://citefoundry.com/problems/not-found 404 — resource doesn't existhttps://citefoundry.com/problems/validation 400 — request body failed validationhttps://citefoundry.com/problems/plan-quota-exceeded 402 — billing limit reachedhttps://citefoundry.com/problems/rate-limited 429 — API rate cap hithttps://citefoundry.com/problems/integration-error 502 — upstream (Google, OpenAI) failedhttps://citefoundry.com/problems/internal 500 — unexpected server errorThe pattern clients should use
Switch on type:
import { ApiError } from "@citefoundry/api-client";
try { await DefaultService.createMonitor({ projectId, requestBody });} catch (err) { if (!(err instanceof ApiError)) throw err;
switch (err.body?.type) { case "https://citefoundry.com/problems/plan-quota-exceeded": return showUpgradePrompt(err.body); case "https://citefoundry.com/problems/rate-limited": // err.body.retryAfter is seconds return waitAndRetry(err.body.retryAfter); case "https://citefoundry.com/problems/validation": // err.body.errors is the per-field detail return showValidationErrors(err.body.errors); default: throw err; }}Validation errors
validation problems carry an additional errors array, one per
invalid field:
{ "type": "https://citefoundry.com/problems/validation", "title": "Validation failed", "status": 400, "detail": "The request body failed validation.", "errors": [ { "path": "cadence", "code": "enum", "message": "must be one of: daily, weekly" }, { "path": "promptId", "code": "required", "message": "is required" } ]}Don’t parse detail
detail is for humans. We reserve the right to reword it for clarity
or localization. Switch on type, surface title in your UI, and use
detail as a fallback message — never as a feature flag.
Related
- Authentication — how to avoid 401s.
- Pagination — the cursor format that returns
validationproblems if malformed. - SDK error handling — full client-side pattern including 401-refresh-retry.