claude-code - 💡(How to fix) Fix [BUG] Bash tool dispatch with sandbox stalls 8-16s between permission decision and shell spawn; UI frozen during stall [2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#56274Fetched 2026-05-06 06:32:30
View on GitHub
Comments
2
Participants
2
Timeline
8
Reactions
0
Author
Timeline (top)
labeled ×6commented ×2

This issue only reproduces when Claude Code's Bash sandbox is enabled (the default on Linux, using bwrap). With the sandbox enabled, every Bash tool call stalls ~8-16 seconds between tool_dispatch_start and Spawning shell without login, with no log output in the gap. The UI is frozen throughout — the spinner animation and elapsed-time counter stop, and the terminal does not respond to resize or Ctrl+C until Spawning shell is logged.

The stall does not depend on workspace size. Reproduced on two separate sessions on the same workstation: one with ~30 git repos under cwd and 53 bwrap binds (8-16 s), and one with a single repo and 38 bwrap binds (14-15 s). Cost per call is effectively constant.

The underlying sandbox binary (bwrap) and shell snapshot are fast (~170 ms combined when measured directly), so the stall is in Claude Code's own Node code that prepares each dispatch, blocking the main/render thread. Disabling the sandbox for a single call (dangerouslyDisableSandbox: true) collapses the gap from ~15 000 ms to ~80 ms (total dispatch ~445 ms), confirming the sandbox-enabled dispatch-prep path is the culprit — not the Bash tool in general, not bwrap itself.

Parallel Bash tool calls issued in a single message do not overlap: each serializes on the dispatch queue and pays the full stall. Four concurrent /bin/true calls took ~4 × 15 s, not 1 × 15 s.

Error Message

T+09.014 [WARN] [Stall] tool_dispatch_end tool=Bash outcome=error durationMs=9014

Error Messages/Logs

Root Cause

Impact

Every Bash tool call costs ~14-16 s before the actual command runs (regardless of workspace size), and the UI is unresponsive during the entire stall. Iterative shell work (grep, git, test runs) becomes painful, and users reasonably assume the CLI has hung. Batching calls in a single parallel message does not help because they serialize on the dispatch queue.

Fix Action

Fix / Workaround

Bash tool dispatch stalls 8-16s between permission decision and shell spawn; UI frozen during stall

Summary

This issue only reproduces when Claude Code's Bash sandbox is enabled (the default on Linux, using bwrap). With the sandbox enabled, every Bash tool call stalls ~8-16 seconds between tool_dispatch_start and Spawning shell without login, with no log output in the gap. The UI is frozen throughout — the spinner animation and elapsed-time counter stop, and the terminal does not respond to resize or Ctrl+C until Spawning shell is logged.

The underlying sandbox binary (bwrap) and shell snapshot are fast (~170 ms combined when measured directly), so the stall is in Claude Code's own Node code that prepares each dispatch, blocking the main/render thread. Disabling the sandbox for a single call (dangerouslyDisableSandbox: true) collapses the gap from ~15 000 ms to ~80 ms (total dispatch ~445 ms), confirming the sandbox-enabled dispatch-prep path is the culprit — not the Bash tool in general, not bwrap itself.

Code Example

T+00.000 [INFO]  [Stall] tool_dispatch_start tool=Bash permissionDecisionMs=3
T+00.002 [DEBUG] Creating shell snapshot for bash (/bin/bash)
T+00.008 [DEBUG] Creating snapshot at: <snapshot-path>
T+00.504 [DEBUG] Shell snapshot created successfully (38360 bytes)
T+00.505 [DEBUG] No session environment scripts found
                 ~8 330 ms gap, no log lines
T+08.836 [DEBUG] Spawning shell without login (-l flag skipped)
T+09.014 [WARN]  [Stall] tool_dispatch_end tool=Bash outcome=error durationMs=9014

---

T+00.000 [INFO]  [Stall] tool_dispatch_start tool=Bash permissionDecisionMs=7
                 16 449 ms gap, no log lines
T+16.449 [DEBUG] Spawning shell without login (-l flag skipped)
T+16.756 [INFO]  [Stall] tool_dispatch_end tool=Bash outcome=ok durationMs=16756

---



---

grep -E "\[Stall\]|Spawning shell without login" ~/.claude/debug/latest
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

What's Wrong?

Bash tool dispatch stalls 8-16s between permission decision and shell spawn; UI frozen during stall

Summary

This issue only reproduces when Claude Code's Bash sandbox is enabled (the default on Linux, using bwrap). With the sandbox enabled, every Bash tool call stalls ~8-16 seconds between tool_dispatch_start and Spawning shell without login, with no log output in the gap. The UI is frozen throughout — the spinner animation and elapsed-time counter stop, and the terminal does not respond to resize or Ctrl+C until Spawning shell is logged.

The stall does not depend on workspace size. Reproduced on two separate sessions on the same workstation: one with ~30 git repos under cwd and 53 bwrap binds (8-16 s), and one with a single repo and 38 bwrap binds (14-15 s). Cost per call is effectively constant.

The underlying sandbox binary (bwrap) and shell snapshot are fast (~170 ms combined when measured directly), so the stall is in Claude Code's own Node code that prepares each dispatch, blocking the main/render thread. Disabling the sandbox for a single call (dangerouslyDisableSandbox: true) collapses the gap from ~15 000 ms to ~80 ms (total dispatch ~445 ms), confirming the sandbox-enabled dispatch-prep path is the culprit — not the Bash tool in general, not bwrap itself.

Parallel Bash tool calls issued in a single message do not overlap: each serializes on the dispatch queue and pays the full stall. Four concurrent /bin/true calls took ~4 × 15 s, not 1 × 15 s.

Environment

  • Claude Code 2.1.128 (native install)
  • RHEL 9.7, kernel 5.14
  • bubblewrap 0.6.3
  • Node 22 (bundled with native install)
  • Model: claude-opus-4-7 via AWS Bedrock
  • Home on local XFS (not NFS)
  • Not inside tmux/zellij (TERM=xterm-256color)

Two cwd configurations tested on the same workstation:

  • Session A: workspace root with ~30 nested git repos → 53 bwrap binds (30 × .git/config, ~10 .idea/.vscode, ~10 sensitive-path masks, etc.)
  • Session B: single-repo cwd (one monorepo) → 38 bwrap binds (3 × .git/config)

Reproduction

Ask Claude Code to run trivial Bash commands (/bin/true, echo hi). The stall is consistent across workspace sizes.

Session A: ~30 repos, 53 bwrap binds

Callsandboxtool_dispatch_start → Spawning shelltotal dispatch
Bash #1 (sequential)on~8 300 ms9 014 ms
Bash #2 (sequential)on~8 500 ms8 728 ms
Bash #3 (4 requested in parallel)on16 449 ms16 756 ms
Bash #4 (4 requested in parallel)on15 353 ms15 694 ms
Bash #5 (4 requested in parallel)on15 447 ms15 799 ms
Bash #6 (4 requested in parallel)on15 775 ms16 142 ms
Bash (same workstation, same cwd)off~80 ms445 ms

Session B: 1 repo, 38 bwrap binds

Callsandboxtool_dispatch_start → Spawning shelltotal dispatch
Bash #1 (sequential)on15 362 ms15 619 ms
Bash #2 (sequential)on14 114 ms14 356 ms
Bash #3 (sequential)on15 175 ms15 504 ms
Bash #4 (requested in parallel)on14 802 ms15 081 ms
Bash #5 (requested in parallel)on14 818 ms15 060 ms
Bash #6 (requested in parallel)on14 956 ms15 189 ms

Observations:

  • Workspace size does not meaningfully change the cost. 53 binds vs 38 binds produced the same order-of-magnitude stall.
  • Parallel requests serialize. Tool calls issued in a single parallel message had dispatch_start timestamps 15-18 s apart (no overlap). The cost is paid once per call, not amortized across a batch.
  • Sandbox off collapses the cost. Same workstation, same cwd: ~80 ms gap instead of 15 000+ ms. This confirms the sandbox-enabled dispatch-prep path is the culprit — not the Bash tool in general, not bwrap itself.

Representative log excerpts from ~/.claude/debug/latest

Sequential case (Bash #1):

T+00.000 [INFO]  [Stall] tool_dispatch_start tool=Bash permissionDecisionMs=3
T+00.002 [DEBUG] Creating shell snapshot for bash (/bin/bash)
T+00.008 [DEBUG] Creating snapshot at: <snapshot-path>
T+00.504 [DEBUG] Shell snapshot created successfully (38360 bytes)
T+00.505 [DEBUG] No session environment scripts found
                 ~8 330 ms gap, no log lines
T+08.836 [DEBUG] Spawning shell without login (-l flag skipped)
T+09.014 [WARN]  [Stall] tool_dispatch_end tool=Bash outcome=error durationMs=9014

Concurrent case (Bash #3 — snapshot already cached):

T+00.000 [INFO]  [Stall] tool_dispatch_start tool=Bash permissionDecisionMs=7
                 16 449 ms gap, no log lines
T+16.449 [DEBUG] Spawning shell without login (-l flag skipped)
T+16.756 [INFO]  [Stall] tool_dispatch_end tool=Bash outcome=ok durationMs=16756

Other subsystems (FileIndex, MCP, API streams, file-permission cache writes) keep logging in other windows while this gap occurs, so it is not general log buffering — it is unlogged code on the hot path.

UI symptom: frozen render during stall

Throughout the 8-16 second window, the spinner animation and elapsed-time counter both freeze. The UI thread appears blocked, not just slow — there is no "thinking" animation, the timer stops incrementing, and the terminal does not respond to resize or Ctrl+C until Spawning shell is logged. Consistent with a synchronous code path on the main/render thread that never yields to the event loop.

Independent benchmarks (ruling out the environment)

Measured on the same host, outside the stall window:

StepTime
bwrap --unshare-net --unshare-pid + 30 --ro-bind + /bin/true13 ms
bwrap ... + socat proxy setup + /bin/true13 ms
Sourcing the shell snapshot (562 lines, 38 KB)152 ms
find <workspace> -maxdepth 6 \( -name .git -o -name .idea -o -name .vscode \)76 ms
/bin/true~4 ms

Total explainable cost: ~170 ms (once snapshot is cached, which it is by call #2). The missing 8-16 seconds are not attributable to bwrap, kernel namespaces, shell snapshot sourcing, or filesystem walks.

Sandbox invocation details

For context, the bwrap command assembled per Bash call contains:

  • --unshare-net --unshare-pid --new-session --die-with-parent
  • Session A: 53 --bind/--ro-bind operations (30 × <repo>/.git/config, ~10 .idea/.vscode directory binds, ~10 sensitive-path masks e.g. /dev/null~/.ssh/id_ed25519, plus standard workspace binds: cwd, /tmp, .npm/_logs, .claude/debug).
  • Session B: 38 --bind/--ro-bind operations (3 × .git/config only; otherwise same structure).
  • Env-var setup for HTTP/SOCKS proxies bridged via socat.

In Session A, several of the .git/config bind entries are exact duplicates in the argv — suggesting deduplication is missing even within the current per-call assembly. Not a performance concern at this scale, but it is a hint that the bind list is rebuilt from scratch each call.

Hypotheses (please verify)

Since cost is ~constant across workspace sizes, the bottleneck is likely a fixed-size per-call step rather than anything that scales with cwd:

  1. Permission rule compilation re-materialized per call. Both sessions load similar settings (35 deny + 26 ask rules + allow rules). If these are recompiled (e.g. regex build, glob-to-path resolution) per dispatch, the cost would be roughly constant across workspaces.
  2. Fixed-size set of synchronous syscalls on the main thread. The dispatch-prep path may stat/readdir a fixed candidate set (home dotfiles, sensitive-path targets to mask, known config locations) per call. Would explain both the ~constant duration and the UI freeze.
  3. Per-call initialization unrelated to the filesystem — e.g. re-reading the settings.json hierarchy and re-resolving per-tool permission state. Consistent with tool calls being strictly serialized on the dispatch queue.

Request

  • Add tracing for the tool_dispatch_start → Spawning shell interval so the expensive step is visible in debug logs. Right now it is entirely opaque.
  • Cache sandbox policy / bind list per session. The first call may legitimately need to enumerate the workspace; subsequent calls should not repeat the work. Invalidate on config/cwd change.
  • Move dispatch-prep off the render thread, or yield periodically (e.g. setImmediate between syscalls), so the UI remains responsive even when prep is slow.

Impact

Every Bash tool call costs ~14-16 s before the actual command runs (regardless of workspace size), and the UI is unresponsive during the entire stall. Iterative shell work (grep, git, test runs) becomes painful, and users reasonably assume the CLI has hung. Batching calls in a single parallel message does not help because they serialize on the dispatch queue.

What Should Happen?

No repeating stalls

Error Messages/Logs

Steps to Reproduce

  1. Use Claude Code 2.1.128 native install on Linux, with the default Bash sandbox enabled (bwrap present on PATH, sandbox not disabled in settings).
  2. Start Claude Code with debug logging enabled: claude --debug (or CLAUDE_CODE_DEBUG=1 claude). This makes [Stall] lines show up in ~/.claude/debug/<session>.txt (symlinked from ~/.claude/debug/latest).
  3. From any project directory, ask Claude to run a trivial Bash command, e.g.:

    Run /bin/true.

  4. Observe: the spinner and elapsed-time counter freeze for ~8-16 s before the command output appears.
  5. Ask Claude to run four trivial Bash commands in a single parallel tool batch, e.g.:

    Run /bin/true four times in parallel in one message.

  6. Observe: the four calls serialize; each pays the full stall, total wall time ≈ 4 × 15 s.
  7. Confirm the stall is in the sandbox path by asking Claude to run the same command with the sandbox disabled (dangerouslyDisableSandbox: true). The stall collapses to ~80 ms.
  8. Inspect ~/.claude/debug/latest and grep for Stall:
    grep -E "\[Stall\]|Spawning shell without login" ~/.claude/debug/latest
    Each Bash call shows a multi-second gap between tool_dispatch_start and Spawning shell without login (-l flag skipped) with no log lines in between.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

No response

Claude Code Version

2.1.128 (Claude Code)

Platform

AWS Bedrock

Operating System

Other Linux

Terminal/Shell

Other

Additional Information

No response

extent analysis

TL;DR

The likely fix involves optimizing the sandbox-enabled dispatch-prep path in Claude Code, potentially by caching the sandbox policy or bind list per session, to reduce the 8-16 second stall between tool_dispatch_start and Spawning shell without login.

Guidance

  • Investigate the permission rule compilation process to determine if it is being re-materialized per call, and consider caching the results to reduce the constant per-call step.
  • Review the dispatch-prep path to identify any fixed-size sets of synchronous syscalls on the main thread that could be causing the UI freeze, and consider moving them off the render thread or yielding periodically.
  • Add tracing for the tool_dispatch_start → Spawning shell interval to make the expensive step visible in debug logs.
  • Consider caching the sandbox policy or bind list per session to avoid repeating the work for subsequent calls.

Example

No code example is provided as the issue is related to the internal implementation of Claude Code and requires modifications to the existing codebase.

Notes

The issue is specific to the Claude Code implementation and requires a deep understanding of the codebase to resolve. The provided guidance is based on the information provided in the issue and may not be exhaustive.

Recommendation

Apply a workaround by disabling the sandbox for specific Bash commands or consider upgrading to a future version of Claude Code that may address this issue, if a fix is implemented. The reason is that the current version (2.1.128) has a known performance issue with the sandbox-enabled dispatch-prep path.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [BUG] Bash tool dispatch with sandbox stalls 8-16s between permission decision and shell spawn; UI frozen during stall [2 comments, 2 participants]