Claude Code printed steps 1, 2, and 3 of a 5-step task. Then nothing. No error, no “I’m done”, just the spinner still showing esc to interrupt or a blinking cursor. You wait 60 seconds, then a minute more. The work isn’t finished, the agent isn’t reporting why it stopped, and re-prompting only gets it to step 4 before it stalls again.
Fastest path: First press Esc (or Ctrl+C twice in quick succession) to interrupt the current turn without losing the session, then type a short message like continue from where you stopped. If that does nothing within a few seconds, the turn is genuinely wedged — run git status to see what actually landed, kill any hung tool process, then restart with claude --continue (or claude --resume to pick the session from a list). The work usually survives on the server side; your job is to confirm what’s done and resume without redoing it.
A stuck-after-partial state has three distinct flavors with different fixes: context compaction (the agent summarized its own history and lost the plan), tool hang (a Bash call like pnpm test never returned), or dropped stream (the response stopped reaching your terminal even though the backend kept running). Don’t fight the stuck session — diagnose the flavor, save state, resume from a fresh status doc.
Which bucket are you in?
| Symptom | Most likely cause | First move |
|---|---|---|
| Long session, many tool calls, token counter was near the top before it stalled | Context near full / auto-compact thrash | /compact, or restart with claude --continue |
| A specific command (test, build, dev server) was the last visible action | Tool hang (bash timeout / phantom callback) | Kill the process, then Esc to resume |
| Network blip, VPN reconnect, or laptop slept right before it froze | Dropped stream | Ctrl+C twice, then claude --continue |
git diff shows the work is actually done, only the “done” message is missing | Truncated final message | Nothing — it finished; verify and move on |
Spinner gone but no new output for < 60s | Possibly still reasoning | Wait the full 60s before judging it stuck |
Common causes
Ordered by hit rate, highest first.
1. Context window near full; auto-compaction dropped the plan
Claude Code auto-compacts its own conversation history when context gets near full (the trigger fires around 95% of the window, roughly 25% headroom remaining, as of June 2026). Above ~80% you also get a “pseudo-freeze”: responses slow to a crawl and the token counter creeps, which looks like a hang but isn’t. When compaction runs mid-task, the working plan can get summarized away — the agent finishes what it still remembers and emits nothing, because in its compressed view the task is done.
How to spot it: The session was long with many tool calls, and the context bar was near the top before it stalled. After /clear + a fresh start (or claude --continue into a compacted-then-restarted session), the same prompt finishes — meaning context, not the task, was the limit.
Fix: Run /compact yourself at a clean checkpoint before the bar fills, and steer what it keeps by adding a short # Compact Instructions section to CLAUDE.md (for example: “Always preserve the current task plan and which steps remain”). For a big task, fork at a clean point so the original session never has to compact.
2. A tool call hung; the agent waits for a callback that never comes
pnpm test started but never returned (infinite loop in test setup, a hanging dev server, a watch-mode command that never exits). Claude Code’s bash layer blocks waiting for the command to finish, so no output reaches you. Note the default ceiling: as of June 2026 Claude Code kills a bash command after 2 minutes unless you raise it, but watch-mode or server commands can wedge the turn before the timeout fires, and the bash timeout has a hard ceiling around 10 minutes regardless of config.
How to spot it: The last visible action was a specific command. Check running processes: ps aux | grep -E "node|python|pnpm|vitest". If one is alive but doing nothing (no CPU, no growing output), that’s your culprit.
Fix: Kill it (see Step 3 below). To prevent the recurrence, never let Claude run a watch/serve command directly, and raise the default for legitimately slow commands by adding to ~/.claude/settings.json:
{
"env": {
"BASH_DEFAULT_TIMEOUT_MS": "300000",
"BASH_MAX_TIMEOUT_MS": "600000"
}
}
BASH_DEFAULT_TIMEOUT_MS sets the default (here 5 min); BASH_MAX_TIMEOUT_MS is the cap. Restart Claude Code for the change to take effect. These belong in the env block of settings.json — shell exports are ignored by Claude Code’s internal timeout, and the ceiling tops out around 10 minutes either way.
3. Streaming connection dropped silently
A WiFi blip, VPN reconnect, or laptop sleep cut the streaming response from the server. Claude Code’s HTTP client has no read timeout, so once the upstream stops sending packets mid-transmission the process just sits waiting for data that never arrives. The backend may still be running; you simply stopped seeing output. This is a known class of bug (a final stream event dropped during a state transition, leaving the request neither resolved nor failed), so it can happen even on a stable connection.
How to spot it: The freeze lined up with a network event, or the spinner is stuck and even Esc does nothing.
Fix: Ctrl+C twice to force-stop the wedged turn, then claude --continue to reload the last conversation, or claude --resume to pick it from a list. Server-side state usually lets the work continue.
4. The agent’s plan completed but the work isn’t done
The agent had a 3-step plan internally; you needed 5. After step 3 it considered itself done and stopped emitting. Plan and reality diverged.
How to spot it: Ask Did you complete the task? List the remaining steps. If it says “yes” but you can see incomplete work, its plan was smaller than yours.
Fix: Re-state the full acceptance criteria explicitly (“the task is done only when X, Y, and Z all pass”) so its internal plan matches the real scope.
5. The final “done” message got truncated
A stream limit clipped Claude Code’s final summary. The code was applied, but you never saw the wrap-up. The agent did finish; you just don’t know it.
How to spot it: git status and git diff reveal that the work is done — the stuck appearance was a presentation issue, not a real stall.
6. Long reasoning vs. a real hang — distinguish before restarting
Some extended-thinking steps run 30+ seconds with no token output. Restarting prematurely throws away work in progress.
How to spot it: Wait a full 60 seconds with no output before judging it stuck. If the client still shows a “thinking” indicator or the esc to interrupt hint, the model is still working. (Note: during active tool calls, Esc/Ctrl+C interrupts are a known weak spot and may not register on the first press — give it two.)
Shortest path to fix
Ordered by ROI. Step 1 diagnoses the flavor; the right fix follows from that.
Step 1: Try to interrupt, then diagnose
1. Press Esc, or Ctrl+C twice in quick succession, to stop the current turn
without losing the session. Then type: continue from where you stopped.
2. If nothing responds in a few seconds, run /doctor for a built-in health check.
3. Run `git status` and `git diff` — is the work *actually* incomplete?
4. Check running processes: ps aux | grep -E "node|python|pnpm|vitest" — anything hung?
5. Look at `top` / Activity Monitor — is anything using CPU?
If the diff shows incomplete work AND processes are idle AND it’s been 60+ seconds with no output, the session is genuinely stuck.
Step 2: Capture state before restarting
# Quick checkpoint commit
git add -A && git commit -m "wip: stuck during step N"
# Write what was supposed to happen next
cat > STATUS.md <<EOF
Task: <one-sentence>
Done: steps 1-3 (files A, B, C edited)
Remaining: steps 4-5 (need to edit D, E)
Last action visible: <what Claude was doing>
EOF
This is your resume point. Restarting blind costs more than the two minutes it takes to write this.
Step 3: Kill hung processes if any
# Find the hung tool process
ps aux | grep -E "node|python|pnpm|vitest" | grep -v grep
# Kill orphans (replace PID)
kill -9 <PID>
# Aggressive cleanup if needed
pkill -9 -f vitest
pkill -9 -f "pnpm test"
If killing a hung tool unsticks the session, you found the cause — note which command not to let Claude run directly in future sessions (especially watch/serve commands).
Step 4: Resume with the session and STATUS.md as the handoff
Reload the prior conversation rather than starting cold:
claude --continue # reload the most recent session
# or
claude --resume # pick the session from an interactive list
Then hand it the snapshot:
Read STATUS.md and pick up the task.
Verify against `git log` what's already committed.
Do not redo completed work. Start from "Remaining".
If context was the original cause, run /clear first and start fresh from STATUS.md so no faded plan lingers.
Step 5: If it consistently stalls at the same step, split that step
A step that reliably stalls is usually too large or contains a problematic sub-task. Split it:
Original step 5: "Update all consumers and run integration tests"
Split into:
5a: Update consumer in src/api/users.ts. Stop.
5b: Update consumer in src/api/orgs.ts. Stop.
5c: Run `pnpm test src/api/users.test.ts`. Stop.
5d: Run `pnpm test src/api/orgs.test.ts`. Stop.
Each sub-step is small enough to fit without hitting whatever the failure mode is.
Step 6: For tool hangs, run the troublesome tool yourself first
If pnpm test keeps hanging when Claude runs it, run it yourself in a separate terminal. Once it has started and completed cleanly, tell Claude to skip running it and use the result instead:
I just ran `pnpm test` and it produced the output below.
Use this output; do NOT run the test command yourself.
[paste]
This works around an unreliable tool without abandoning the agent mid-task.
How to confirm it’s fixed
You’re unstuck when all of these are true:
git status/git diffshow every file the task required is edited.- The build/tests you expected actually ran and passed (run them yourself once if unsure).
- A fresh prompt —
List anything still incomplete from STATUS.md— comes back empty.
If any fail, you resumed onto a stale plan; re-run Step 4 with /clear and a fresh STATUS.md.
Prevention
- After every major step, ask Claude to update
STATUS.md— it survives all three flavors of stuck. /compacton purpose at a clean checkpoint instead of waiting for auto-compaction to fire near 95%.- Add a
# Compact Instructionsblock toCLAUDE.mdtelling it to preserve the task plan through compaction. - Cap tasks at roughly an hour of expected agent time; smaller checkpoints survive better.
- Run on a stable network — a mobile hotspot is the silent killer for streaming connections.
- Don’t let Claude run watch/serve commands directly, and split test runs from edits.
- Raise
BASH_DEFAULT_TIMEOUT_MSin~/.claude/settings.jsonfor legitimately slow commands so they don’t get killed at the 2-minute default.
FAQ
Why did Claude Code stop after only part of the task with no error?
Three causes dominate: auto-compaction dropped the plan mid-task, a bash tool call hung past its timeout, or the streaming response dropped while the backend kept running. Run git diff to see whether the work is actually incomplete, then match the flavor using the table above.
Will I lose my work if I restart Claude Code?
Usually not. claude --continue reloads your most recent session and claude --resume lets you pick one from a list, both restoring the context you built. Commit a WIP checkpoint first (git add -A && git commit) so completed edits are safe regardless.
Esc and Ctrl+C don’t stop it — how do I force quit?
Interrupts are a known weak spot during active tool calls. Press Ctrl+C twice in quick succession. If the whole CLI is wedged, find the PID with ps aux | grep claude and kill -9 <PID>, then relaunch with claude --continue.
How do I stop Claude Code from killing my long-running command at 2 minutes?
Add BASH_DEFAULT_TIMEOUT_MS (and optionally BASH_MAX_TIMEOUT_MS) to the env block of ~/.claude/settings.json and restart. Shell environment exports are ignored, and the hard ceiling is around 10 minutes — for anything longer, run it yourself and feed the output back.
What does /compact do, and should I run it manually?
/compact summarizes the session history to free context while keeping a recap. Running it deliberately at a clean checkpoint avoids the mid-task auto-compaction that drops your plan. Use /clear instead when you want a hard reset with no carried-over history.
Related
- Claude Code stuck in a loop
- Claude Code stops mid-task due to usage limits
- Claude Code lost project context mid-task
- Claude Code beginner guide
- Claude Code workflow
- Claude Code project setup
Tags: #Troubleshooting #Claude Code #Debug #Partial execution