Skip to content

API

Error reference

4 min readUpdated

Page actions

ChatGPT and Claude are third-party services. The link gives them this page's public address and a short instruction. This site records nothing.

Every error the API returns — status, legacy body and /api/v1 envelope — generated by calling the server, plus the requests that are clamped or empty instead.

Every error below was produced by calling the server’s own handler, on both surfaces, when this page was generated; CI regenerates it and fails if a status, a message or an envelope has changed. A client should branch on the status (and, on /api/v1, the code), never on the message text.

The two shapes

/api/… (legacy)/api/v1/…
Bad parameter400, {"error": "invalid request: <message>"}400, {"error": {"code": "invalid_request", "message", "request_id"}}
Not found (a gap, an unknown bani)404, {"error": "<message>"}404, code not_found
Unknown endpoint400, {"error": "invalid request: unknown endpoint"}404, code not_found
Unexpected failure500, {"error": "internal server error"}500, code internal, message internal server error

The legacy shape is frozen: the golden contract and the app depend on it byte for byte. New clients should use /api/v1, whose request_id is the same id as the X-Request-Id header and the access log (versioning and caching). A 500 never carries the exception; the detail is only in the server log, under that request id.

Every error, as the server answers it

RequestWhenStatusLegacy body/api/v1 code · message
/api/nopea path that is not a route400 · v1 404{"error": "invalid request: unknown endpoint"}not_found · no such endpoint: /api/v1/nope
/api/anga route that needs an id, without one400{"error": "invalid request: /api/ang requires an id"}invalid_request · /api/ang requires an id
/api/ang/abcan id that is not an integer400{"error": "invalid request: integer parameter expected"}invalid_request · integer parameter expected
/api/ang/1234567890123an integer longer than 12 characters400{"error": "invalid request: integer parameter too long"}invalid_request · integer parameter too long
/api/search?q=naam&limit=abcan integer parameter that is not an integer400{"error": "invalid request: integer parameter expected"}invalid_request · integer parameter expected
/api/shabad/1a comp_id that is a permanent gap404{"error": "no composition with comp_id 1"}not_found · no composition with comp_id 1
/api/shabad/99999999a comp_id beyond the last composition404{"error": "no composition with comp_id 99999999"}not_found · no composition with comp_id 99999999
/api/search?q=‹301 characters›a search query over 300 characters400{"error": "invalid request: query too long (max 300 chars)"}invalid_request · query too long (max 300 chars)
/api/verify?q=an empty claim400{"error": "invalid request: empty claim"}invalid_request · empty claim
/api/verify?q=‹601 characters›a claim over 600 characters400{"error": "invalid request: claim too long (max 600 chars)"}invalid_request · claim too long (max 600 chars)
/api/bania bani without its key400{"error": "invalid request: /api/bani requires a key"}invalid_request · /api/bani requires a key
/api/bani/NOPE!a key with characters a key never has400{"error": "invalid request: bad bani key"}invalid_request · bad bani key
/api/bani/nopea well-formed key that is not a bani404{"error": "no bani with key nope"}not_found · no bani with key nope
/api/bani/japji?variant=zza variant that is not one of the bani’s400{"error": "invalid request: bad variant"}invalid_request · bad variant
/api/analytics/progressionprogression without raag400{"error": "invalid request: progression requires a raag"}invalid_request · progression requires a raag
/api/timing/raaga raag lookup without name400{"error": "invalid request: timing/raag requires ?name="}invalid_request · timing/raag requires ?name=
/api/forms?comp_id=0forms without a usable comp_id400{"error": "invalid request: forms requires ?comp_id="}invalid_request · forms requires ?comp_id=

Not errors

Most parameters are clamped to their range rather than rejected, and some malformed input simply finds nothing. These requests all return 200; check the body, not only the status:

RequestWhat happensStatusBody (lists shown as their length, Gurmukhi as ‹Gurmukhi›)
/api/ang/0an Ang below 1 is clamped to 1200{"ang": 1, "lines": [23 items], "continued_from": null, "raag": null, "section": ‹Gurmukhi›, "authors": [1 item]}
/api/ang/1431an Ang above 1430 is clamped to 1430200{"ang": 1430, "lines": [57 items], "continued_from": 1429, "raag": null, "section": ‹Gurmukhi›, "authors": [1 item]}
/api/search?q=naam&limit=999limit above 200 is clamped to 200200{"mode": "theme", "concept": {…}, "results": [200 items], "related_themes": [0 items]}
/api/lines?ids=abcids that are not digits are ignored200{"lines": [0 items], "note": "verbatim Gurmukhi by line id, cited by Ang"}
/api/analytics/vaar?id=xa Vaar id that is not a number finds no Vaar200{"vaar": null, "units": [0 items]}
/api/wordno word: nothing to count200{"word": "", "count": 0, "lines": [0 items]}
/api/neighborsno line_id: no neighbours200{"line_id": 0, "level": "none", "neighbors": [0 items]}
/api/timing/raag?name=nopean unknown raag name: no claims200{"available": true, "raag": "nope", "claims": [0 items], "note": "no such raag"}

Beyond a single request

  • 404 from a single-context service. A service that runs one context answers a route it does not own with 404 and the message /api/<route> is not served by this service. Through the public origin the gateway always sends a route to its own service, so a client only sees this when calling a function directly (bounded contexts and the gateway).
  • 503 from /readyz. {"ready": false, …} when a declared table is missing, or {"ready": false, "error": "database unavailable"}. /healthz is liveness only.
  • The platform in front. Vercel may answer before the API does, for example a timeout or a challenge page for an unusual burst of requests. Such responses are not JSON from this API and carry no X-Service header.