CLI: a slow afterAgentThought hook causes "Connection lost" retries and "Server error / The server failed 4 times"

Where does the bug appear (feature/product)?

Cursor CLI

Describe the Bug

If an afterAgentThought hook is still running when the answer finishes, the CLI thinks the connection was lost. It retries, prints the answer again, and after 4 tries shows “Server error. The server failed 4 times.”

Nothing was actually lost. The answer had finished normally.

What I see:

  • Connection lost, reconnecting to https://api2.cursor.sh (attempt 1)... Retry attempt 1... and the answer printed twice.
  • In the normal (interactive) CLI, the model thinks again on each retry, so it fails again. After 4 tries: Error: Server error. The server failed 4 times.
  • In -p mode the final error is RetriableError: WritableIterable is closed.

It only happens with models that have thinking on, because only they trigger afterAgentThought.

Steps to Reproduce

  1. Add a hook that just waits 1 second, in ~/.cursor/hooks.json:
{"version":1,"hooks":{"afterAgentThought":[{"command":"sleep 1"}]}}
  1. Run:
cursor-agent -p --trust --model claude-opus-5-5-medium "Is 391 prime? Think first, then answer in one short sentence."

You get “Connection lost, reconnecting” and the answer twice.

  1. To get the “Server error”, run the normal CLI with a prompt that makes the model think on every reply:
cursor-agent --model claude-opus-5-5-medium "Before every reply you write, including any continuation, always think step by step first. Is 391 prime? Answer in one short sentence."

I tried hooks that wait 1, 2, 3, 5 and 10 seconds. All of them failed 3 out of 3 times. For a short answer, the answer ends less than a second after the hook starts, so even a 1 second hook is too slow.

Expected Behavior

One answer and no retry. If a hook finishes after the answer is done, the CLI should just ignore it.

Operating System

MacOS

Version Information

Cursor CLI 2026.11.11-b912975 (also 2026.10.14, 2026.10.19, 2026.10.22), macOS arm64, network.useHttp1ForAgent: true.
The desktop app (3.27.14) has the same problem in its logs, but it ignores the error, so users don’t see it there.

For AI issues: which model did you use?

Any model with thinking enabled (Opus 5.5, Sonnet 5 Thinking, Haiku 5.5 with thinking, Grok 4.7, Codex 5.3)

Additional Information

What happens, step by step:

  1. The model finishes a thought. The server asks the CLI to run the afterAgentThought hooks.
  2. While the hooks run, the CLI sends the server “still working” every 3 seconds, and “done” when they finish.
  3. Meanwhile the answer finishes, and the CLI closes its connection to the server.
  4. The hook is still running. When it sends “still working” or “done”, the connection is already closed, so sending fails (WritableIterable is closed).
  5. The CLI reports this as LostConnection, counts it as a server error, and retries. On the retry the model thinks again, the same thing happens, and after 4 tries the CLI shows “Server error”.

The CLI already has a check that ignores these errors (“Ignoring handler errors after terminal checkpoint”), but it only works when the server’s last message arrives in a certain order. In the desktop app it always worked. In the CLI it never did.

Log from one run:

hook starts                                 10:41:39.18
answer finished (turnEnded)                 10:41:39.97
LostConnection, counted as server error     10:41:42.18
retry 1                                     10:41:44.43
hook finishes (took 7.4 s)                  10:41:46.54

Does this stop you from using Cursor

Sometimes - I can sometimes use Cursor

Hey @hxgil-r, this is on our side, not your hook. The turn finishes normally while the afterAgentThought hook is still running, and when the hook reports back the CLI treats the already-closed stream as a lost connection and retries. I’ve passed this to the team with your repro.

For now, the only reliable way to avoid it in the CLI is to take the afterAgentThought entry out of hooks.json for CLI runs. Having the hook hand its work to a background process and exit right away narrows the window, but a short answer can still finish first.

This looks like the same issue as this earlier thread.