Errors
Every code, and what it wants you to do.
One envelope everywhere: { "error": { "code", "message" } }. The code is stable and safe to switch on; the message is written for a person reading a response and may change. Two of these codes are not failures at all.
not_carried is not no_edition_on_file
This is the distinction to get right, and it is the reason we never answer a miss with a nearest guess. Both are 404. They mean opposite things, and an agent that conflates them will go and cite something wrong.
It is not hypothetical. A jubal.law agent asked for a Florida court rule. We carried no state court rules at the time, but the answer came back as no_edition_on_file with a message written for Florida statutes. The agent read “we have this material, just not that number”, went to the open web, and cited a superseded rule.
not_carried — stop
We hold nothing of that material for that jurisdiction. No citation within it can be confirmed or denied by us, and nothing you find elsewhere carries our authority. The correct behaviour is to tell the user the source is not carried — not to search somewhere else and present the result as though it came from here. /v1/law/coverage lists what is carried.
{
"error": {
"code": "not_carried",
"message": "binding.law does not carry FL rules. This is a stated gap, not a lookup failure: nothing of that material for that jurisdiction is in the corpus, so no citation within it can be confirmed or denied, and nothing found elsewhere on the open web carries binding.law's authority. See /v1/law/coverage for what is carried."
}
}no_edition_on_file — look again
We carry that material. This particular key is not on file, or nothing under it was in force on the date you asked for. Three things to check: the form of the key, the asOf date against that jurisdiction’s coverageFrom, and error.didYouMean when it is present.
{
"error": {
"code": "no_edition_on_file",
"message": "binding.law carries FL statutes, but has no section matching 768.99 on file for 2026-09-20. We never resolve to a nearest edition. Coverage begins at the date reported for FL statutes in /v1/law/coverage; a citation outside that window, or a key in a different form, both land here."
}
}When the number you asked for exists under a fuller key, the miss names the candidates rather than picking one. Florida’s 401.14 is a different instruction in the civil set and in the contract and business set; guessing one would be worse than offering both.
{
"error": {
"code": "no_edition_on_file",
"message": "No FL jury instructions is keyed exactly \"401.14\", but these keys match it: civil-401.14, contract-401.14. Retry with one of them — they are different instruments, so pick by publication rather than assuming the first. Nothing has been guessed on your behalf.",
"didYouMean": [
{ "citationKey": "civil-401.14", "citationDisplay": "Fla. Std. Jury Instr. (Civ.) 401.14" },
{ "citationKey": "contract-401.14", "citationDisplay": "Fla. Std. Jury Instr. (Contract & Bus.) 401.14" }
]
}
}Illustrative keys. The didYouMean array carries up to five candidates, each with its citationKey and its citationDisplay, and appears only when a suffix match was found within the carried material.
On MCP, a not_carried body additionally carries a note field merged into the JSON, repeating the instruction in the form a model will act on. See the MCP page.
The full list
Authentication and limits
No Authorization header, or one whose token after Bearer is empty.
Send Authorization: Bearer <key>. Coverage, quality and health need no key at all.
The key did not match an active record. Revoked keys answer identically.
Check the key was copied whole, and that it has not been revoked. Keys are shown once; reissue rather than hunt.
The key is valid but lacks the scope the endpoint requires. Every law endpoint requires lookup.
Issue a key with the lookup scope. The message names the scope it wanted.
The key's per-minute request ceiling. A coarse 120/minute edge limit can also produce this.
Honour Retry-After, which is 60. Spread the burst.
The key's daily billable-unit cap. Windows are UTC.
Retry-After carries the seconds until 00:00 UTC — use it rather than retrying every minute.
The key's monthly billable-unit cap.
Retry-After carries the seconds until the 1st. Raise the plan or the cap.
Request validation
A required parameter is absent: jurisdiction or citation on lookup and text; q on search; jurisdiction on format; a usable body on citation lookup.
The message names what was wanted. On MCP, citation can also arrive under its alias key.
asOf is not YYYY-MM-DD.
Send a plain date. There is no time component; it is resolved at noon UTC internally.
corpus is not one of statutes, regulations, guidance, jury_instructions, rules, guidelines.
Use one of the six. The list is closed and the message repeats it.
level on /law/format is not one of trial, intermediate-appellate, supreme, specialty.
Use one of the four, or drop the filter and read level off each record.
fallback on citation lookup is not "none" or "courtlistener".
Omit it for none.
clusterId in a /law/cases path is not a positive integer.
Cluster ids are integers. Pull one from a citation-lookup result's clusters[].id.
More than 250 citations were parsed out of a citation-lookup body.
Batch the request.
text on citation lookup exceeds 64,000 characters.
Split the document. The limit matches CourtListener's own.
Misses
binding.law holds nothing of that material for that jurisdiction. Also returned by /law/format when no record exists, and by /law/search when a single named jurisdiction holds nothing of that corpus.
Stop. Do not look elsewhere on binding.law's authority. Say the source is not carried, and check /v1/law/coverage for what is.
The material is carried, but nothing matches that citation key, or nothing was in force on that date.
Read error.didYouMean if present, check the key's form, and check asOf against that jurisdiction's coverageFrom.
No case cluster with that id. Case-law only.
Resolve a citation first and use the cluster id it returns.
Server and dependency
The query failed. The message names which operation — lookup, search, format, citation lookup.
Retry once. If it persists, check /v1/health/corpus and tell us.
The law corpus store is not configured or not reachable from this deployment.
Retry with backoff. /v1/health/corpus answers the same question directly and is the endpoint to monitor.
The case-law replica is not configured on this deployment.
Retry with backoff. Law endpoints are unaffected — the two stores are separate.
MCP transport errors
The MCP endpoint answers in JSON-RPC rather than the HTTP error envelope. Two codes:
Everything else — a 404 miss, a 400, a 429 — arrives as an ordinary tool result carrying the REST error body, because an explicit miss is information rather than a transport failure.
Two signals that are not errors
stale on a coverage response. Coverage is served from a cache refreshed behind the response. Past an hour without a successful refresh the payload grows a stale object with ageSeconds, refreshFailures and lastError. The status is still 200 — a stale count beats an outage for a public matrix — but the numbers are labelled so a silent refresh failure cannot look healthy. It exists because a rotated database password once let coverage serve pre-rotation totals for ten hours while ingests were landing.
stale: true on a filing-format record. A record is our reading of the rules, pinned to the content hash of the rule row it was read from. stale is true when a cited rule’s in-force text no longer matches that pin, or when no row is in force; staleDetail says which rule and which way. Do not certify a filing against a stale record — re-read the rule through /v1/law/lookup?corpus=rules.