Troubleshooting · core
Use when
A read returned
read_deadline_exceeded, HTTP status 503, or retry_after_seconds.Looking for something else?
A write that returned
graph_write_busy (problem A Graph write returned graph_write_busy). A write with no reply or outcome: unknown (problem The reply to a change was lost).Signs
- The refusal code is
read_deadline_exceeded, with HTTP status 503. - The refusal has
retry_after_seconds: 2and the headerRetry-After: 2. - The message reads
read_deadline_exceeded: The read did not finish in time. Nothing was changed. Retry the same request. - In an MCP tool, the result is an error whose text starts with
read_deadline_exceeded:. - The
penumbracommand exits with code 5.
Why it happens
Every read has a deadline. A point read or a page has 10 seconds. A search, a Context read or an Omnisearch has 30 seconds. The read was too slow, or the database was too busy to answer in time. Penumbra stopped the statement in the database, so it does not keep running and does not hold a connection that other requests need.What Penumbra does
By itself:- Stops the read at its deadline, in the database. The statement does not continue after the refusal.
- Stops the read at once when the caller disconnects.
- Answers
read_deadline_exceededwith status 503. A read changes nothing, so the same request is safe to send again.
- Wait
retry_after_seconds. - Send the same read again. If it times out again, ask for less: a smaller page or a narrower search.
- The CLI and the SDK do not retry a read for you after a 503.
Do
- Wait
retry_after_seconds. The value is 2 seconds. - Send the same read again.
- If the read times out twice, ask for less. Use a smaller page, a narrower filter or a more specific search.
- If a narrow read still times out, tell the person. Keep the request that failed.
Don’t
- Don’t send the read again at once in a loop. A busy database needs time.
- Don’t treat the refusal as an empty result. A timed-out search says nothing about whether the project holds the answer.
- Don’t confuse it with
graph_write_busy. That refusal answers a write that waited for another write. This refusal answers a read that ran too long.
Check
- The retry returns the result, or a different refusal.
- A narrower read of the same project returns in time.