Error: Timeout waiting after 1000ms
The number is the diagnosis. One second is far too short to be a request to a language model, so whatever gave up here was waiting on something local: a process, a handle, a lock, a socket, a file. That rules out the vendor being down, your API key, your quota, your context window and your network path in a single stroke — none of those can be established, exhausted or exceeded inside 1000 ms.
Data as of 2026-09. Vendor limits and defaults change; check the official docs for current values before acting on any number below.
Why the number settles it
Claude Code’s per-request API timeout, API_TIMEOUT_MS, defaults to 600000 ms.
That is the budget for something that has to cross the internet and wait for a
model to think. A one-second budget is three orders of magnitude smaller, and
nobody writes that for a network call on purpose.
The per-tool-call limit for MCP servers is larger still — when MCP_TOOL_TIMEOUT
is unset the default is about 28 hours. So if the operation that failed were
governed by either of the timers people usually reach for, the number in your
message could not have been 1000.
What is left is the class of waits that are supposed to complete immediately: acquiring something already available, connecting to something already listening, reading something already on disk, or waiting for a child process that has already started to signal that it is ready. A one-second budget is what you write when you expect the answer in single-digit milliseconds and want a failure rather than a hang.
“Waiting” is a different verb from “request”
The message does not say a request failed or a response was slow. It says something was waiting. A wait is a poll on a condition — is it ready yet? — and it ends either when the condition becomes true or when the budget runs out.
That distinction changes what you look for. There is no round trip to inspect, no status code, no request id, and no headers. There is only a precondition that did not become true in time. The error string tells you almost nothing about which precondition; the line immediately above it in your output almost always does. Scroll up. The operation that was in progress when this fired — a server starting, a tool call dispatching, a file being opened, an editor integration attaching — is the actual subject of the page you are reading.
And 1000 is a round number, which is another piece of information: it is a default that shipped with something, not a value anyone chose for your machine. Defaults are calibrated for the case where everything is warm and local.
Is retrying useful?
Yes — retry once. It is the cheapest experiment available, and the result of that single retry is the branch point for everything else.
A one-second budget is easily lost to ordinary desktop noise: a security scanner opening a file before your process gets it, a cold page cache, a laptop resuming from sleep, CPU contention while a build or test suite is running, or a read that has to cross a virtual machine’s file share instead of hitting a local disk. None of those are broken; they are slow at exactly the wrong moment. Under any of them the same operation succeeds on the next attempt with no change from you.
The branch point is this: if the retry succeeds, you had a contention problem; if it fails instantly and identically, you have a deterministic one, and no amount of extra waiting will help because the condition is never going to become true. Do not build a longer retry loop before you know which one you have — a loop that eventually succeeds hides a contention problem you could have fixed, and a loop that never succeeds just makes a fast failure slow.
Telling the two apart
Run the same operation five or ten times. This is the whole test. Occasional failures mean contention; failure on every attempt means a broken precondition. Everything below depends on which of those you saw, so do not skip it.
Read the lines above the error. Whatever the tool was doing when it fired
names the component that was waiting. If nothing above it is informative, run the
tool with debug output enabled — /debug inside a session turns on debug logging
and asks Claude to diagnose, and the per-session debug log is written under your
config directory.
Start with everything customized turned off. claude --safe-mode runs with
all plugins, MCP servers and hooks disabled. If the message disappears, the wait
belongs to one of those, not to the core tool, and you can re-enable them one at
a time until it comes back. This is the fastest way to convert a generic string
into a named culprit.
Check whether the work crosses a filesystem boundary. A wait budget that is generous against a local disk is marginal against a share between a host and a virtual machine. If your project lives on a Windows drive that a Linux guest reaches over a share, or on a network drive, that alone can turn a comfortable one-second wait into a coin flip.
Ask who printed it. A bare Error: with no component name often comes from a
wrapper rather than from the CLI itself — the same way
Error: Claude Code process exited with code 1 is printed by VS Code or an SDK
application and identifies nothing on its own. If an IDE extension or your own
script is in the chain, check its output before assuming the tool underneath it
is at fault.
Check whether you configured a small timeout yourself. There is one place in
Claude Code’s own configuration where 1000 is a meaningful boundary: the
per-server MCP timeout, where values below 1000 are ignored. If you set that
option to a small number believing it was in seconds, you did not get what you
intended. Take the current unit and accepted range from the documentation rather
than from this page.
Fixes, keyed to what the repetitions showed
- Occasional, and it correlates with load — retry, and then remove the contention rather than the message. Running a full test suite, a large build or an antivirus scan in parallel with the tool is enough on its own. This is a legitimate place to stop: an intermittent one-second wait on a busy machine is not a defect.
- Occasional, and the work is on a shared or network filesystem — move the
project onto a local disk on the side that is doing the work. Crossing that
boundary is slow enough to matter and, in Claude Code specifically, the
documentation notes that searches spanning the WSL filesystem boundary return
fewer results than expected while
claude doctorstill reports Search as OK. A boundary that degrades tooling silently is not where a repository belongs. - Deterministic, and
--safe-modefixes it — one of your plugins, MCP servers or hooks is waiting for something that never arrives. Re-enable them one at a time. For an MCP server, the startup timer isMCP_TIMEOUTand the per-call limits are separate; a server that never finishes starting is a different fault from one that starts and then hangs. - Deterministic, and it survives
--safe-mode— the precondition itself is broken: something is not running, not listening, or not present. The fix is in that component, and the surrounding log lines identify it. Raising any timeout here converts an instant failure into a slow one and nothing else. - You are on a version older than the one you assumed — run
claude --versionand check the current documentation. The docs version-gate individual behaviours, and the wording of these messages changes often, sometimes within a minor version.
How to confirm it’s fixed
Repetition is the only honest test, because a single clean run is exactly what a contention problem produces by luck. Run the operation five times in a row without the message appearing, and run them under the same conditions that produced it — if it only failed while your test suite was running, confirm it while your test suite is running.
For the deterministic case, confirm the precondition rather than the silence.
If an MCP server was the culprit, /mcp should show it connected. If a file or
socket was being waited on, check that it exists and responds. A quiet terminal
proves only that nothing timed out this time.
Related errors
Timeouts with a much larger number in them are a different animal: they usually did involve the network, and the budget in the message tells you which layer set it. If a login flow gave up, see OAuth error: timeout of 15000ms exceeded; if the installer could not fetch a version, see timeout while fetching the version from stable.
If your tool is counting down a retry interval measured in minutes rather than failing in one second, nothing local is stuck and the problem is on the network path: No response from API with a multi-minute retry explains what a long interval implies. If an MCP server is the component that went quiet, MCP error: Connection closed covers a server that dies rather than one that is merely slow to answer. And if a short wait only fails when your files live across a virtual machine share, Plan9 mount failed: invalid argument is what that boundary looks like when it fails outright instead of merely dragging.
When the message is this generic, the fastest way to place it is by layer rather than by wording: the AI coding error triage tool sorts errors by which component produced them and whether anything ever left your machine.