Skip to content

Launcher hangs at 100% CPU forever (app never starts) due to O(n²) awk over an unbounded launcher.log #747

Description

@juancourville-lang

Summary

The launcher can get stuck before Electron ever starts, spinning one awk process at 100% CPU indefinitely. The app never opens and any tray/menu relaunch hangs the same way. Root cause is the GPU-fatal detection in launcher-common.sh reading the entire launcher.log with quadratic string accumulation, combined with the fact that launcher.log is never rotated/truncated and can grow to tens of MB (in my case 67 MB, flooded by WebRTC audio error spam).

Environment

  • Package: claude-desktop 1.15200.0-2.0.22 (.deb)
  • Electron: 41.5.0
  • OS: Debian 13 (trixie), X11
  • Display backend: X11 (XDG_SESSION_TYPE=x11)

Symptoms

  • App stops launching; tray icon gone.
  • A single awk child of /usr/bin/claude-desktop pegs one core at ~100% and never exits:
juan  82593  bash /usr/bin/claude-desktop
juan  82624  99.9  awk  '/^--- Claude Desktop (Launcher|AppImage) Start...  .cache/claude-desktop-debian/launcher.log
  • launcher.log had grown to 67 MB / ~453k lines / 208 launch sections.

Root cause

_previous_launch_hit_gpu_fatal() (launcher-common.sh:196) runs:

{
    sections[section] = sections[section] $0 "\n"   # <-- O(n²) string growth
}

This accumulates the whole log file into in-memory section strings via repeated concatenation. Awk reallocates and copies an ever-growing string per line, so cost is quadratic in file size. At ~67 MB it effectively never finishes, and setup_electron_env (which calls it) blocks → Electron is never exec'd.

Two compounding problems make this reachable in normal use:

  1. No log rotation. setup_logging() only does mkdir; launcher.log grows without bound across launches.
  2. WebRTC audio spam. During sessions with audio/voice the log fills with thousands of lines/sec like:
    ERROR:.../neteq/comfort_noise.cc:50] No multi-channel support
    ERROR:.../neteq/neteq_impl.cc:826] audio_frame->samples_per_channel_ (480) != output_size_samples_ (480)
    
    A single long session bloats the penultimate section — exactly the one the awk targets.

Impact

Once the log is large enough, the app becomes unlaunchable until the user finds and kills the awk and clears the log. Nothing on screen explains why.

Suggested fixes

  1. Don't scan the whole file. Only the previous launch section is needed. Read the log tail (e.g. last N KB, or seek to the second-to-last --- ... Start --- header) instead of accumulating every section. Even just tail -c <bytes> piped into the matcher would bound the cost.
  2. Avoid O(n²) accumulation. Track only the current/previous section, or scan backwards; never build an unbounded concatenated string.
  3. Rotate/truncate launcher.log. Cap size (e.g. truncate to last N lines if > a few MB) in setup_logging().
  4. Tame the WebRTC audio error spam (or downgrade/suppress those Chromium ERROR lines), which is what drives the log growth in the first place.

Workarounds (for other users hitting this)

  • Kill the stuck awk + launcher, back up and truncate ~/.cache/claude-desktop-debian/launcher.log.
  • Set CLAUDE_DISABLE_GPU=0 in the launch environment. Because of the [[ -v CLAUDE_DISABLE_GPU ]] guard in setup_electron_env, defining the var makes the launcher skip _previous_launch_hit_gpu_fatal() entirely (and =0 keeps hardware acceleration on). A user-level ~/.local/share/applications/claude-desktop.desktop override with Exec=env CLAUDE_DISABLE_GPU=0 /usr/bin/claude-desktop %u makes the bypass stick for tray/menu launches and survives package upgrades.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingformat: debAffects .deb packagespriority: highImportant, should be addressed soontriage: investigatedIssue has been triaged and investigated

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions