mirror of
https://github.com/aaddrick/claude-desktop-debian.git
synced 2026-05-17 08:36:35 +03:00
doctor: surface recent Electron crashes with #583 pointer
Adds _doctor_check_recent_crashes, called from run_doctor before the log-file section. When systemd-coredump shows ≥3 Electron crashes in the last 7 days, surfaces a [WARN] with two workarounds (Settings toggle, CLAUDE_DISABLE_GPU=1) and a link to the tracking issue. Filters by the caller-supplied electron_path when entries match, falls back to all-electron entries with a footnote when they don't (covers AppImage's transient mount paths and other Electron apps installed side-by-side). Silent when coredumpctl isn't on PATH (non-systemd hosts), when there are zero matches, or when the count is below threshold. Co-Authored-By: Claude <claude@anthropic.com>
This commit is contained in:
@@ -436,6 +436,66 @@ JSEOF
|
||||
fi
|
||||
}
|
||||
|
||||
# Surface a warning when systemd-coredump shows N+ recent Electron
|
||||
# crashes. The most common cause on Linux is the GPU process FATAL
|
||||
# exhaustion tracked in #583 — workaround for affected users is the
|
||||
# upstream Settings → disable hardware acceleration toggle, or
|
||||
# CLAUDE_DISABLE_GPU=1 in the environment for headless persistence.
|
||||
#
|
||||
# Arguments: $1 = electron path (e.g.,
|
||||
# /usr/lib/claude-desktop/node_modules/electron/dist/electron)
|
||||
# Used to filter results to claude-desktop's electron when possible;
|
||||
# falls back to all-electron crashes when the path doesn't match
|
||||
# (e.g., AppImage mount paths are transient).
|
||||
_doctor_check_recent_crashes() {
|
||||
local electron_path="${1:-}"
|
||||
command -v coredumpctl &>/dev/null || return 0
|
||||
|
||||
# `coredumpctl list electron` filters by COMM=electron. If the
|
||||
# exact electron_path matches any entry's EXE column, prefer that
|
||||
# tighter count; otherwise fall back to all-electron entries.
|
||||
local listing total_count path_count
|
||||
listing=$(coredumpctl list electron \
|
||||
--since='7 days ago' --no-pager 2>/dev/null) || return 0
|
||||
[[ -n $listing ]] || return 0
|
||||
|
||||
# Drop the header line; count remaining entries.
|
||||
total_count=$(awk 'NR>1 && NF>0' <<< "$listing" | wc -l)
|
||||
((total_count == 0)) && return 0
|
||||
|
||||
if [[ -n $electron_path ]]; then
|
||||
path_count=$(awk -v p="$electron_path" \
|
||||
'NR>1 && index($0, p)' <<< "$listing" | wc -l)
|
||||
else
|
||||
path_count=0
|
||||
fi
|
||||
|
||||
# Use the path-matched count when available; else the unfiltered
|
||||
# count with a footnote so the user knows it may include other
|
||||
# Electron apps (Slack, VSCode, etc.).
|
||||
local count footnote=''
|
||||
if ((path_count > 0)); then
|
||||
count=$path_count
|
||||
else
|
||||
count=$total_count
|
||||
footnote=' (some entries may be from other Electron apps)'
|
||||
fi
|
||||
|
||||
if ((count >= 3)); then
|
||||
_warn "Recent Electron crashes: $count in last 7 days$footnote"
|
||||
_info \
|
||||
'Most common cause: Chromium GPU process FATAL (#583).' \
|
||||
'Try one of:'
|
||||
_info ' Settings → toggle hardware acceleration off → restart'
|
||||
_info ' or set CLAUDE_DISABLE_GPU=1 in the environment'
|
||||
_info \
|
||||
'Tracking:' \
|
||||
'https://github.com/aaddrick/claude-desktop-debian/issues/583'
|
||||
elif ((count > 0)); then
|
||||
_info "Recent Electron crashes: $count in last 7 days$footnote"
|
||||
fi
|
||||
}
|
||||
|
||||
# Run all diagnostic checks and print results
|
||||
# Arguments: $1 = electron path (optional, for package-specific checks)
|
||||
run_doctor() {
|
||||
@@ -923,6 +983,11 @@ print(len(servers))
|
||||
fi
|
||||
fi
|
||||
|
||||
# -- Recent crashes --
|
||||
# Surfaces the GPU process FATAL pattern (#583) before users
|
||||
# notice the in-app "Claude crashed repeatedly" prompt.
|
||||
_doctor_check_recent_crashes "$electron_path"
|
||||
|
||||
# -- Log file --
|
||||
local log_path
|
||||
log_path="${XDG_CACHE_HOME:-$HOME/.cache}"
|
||||
|
||||
@@ -229,3 +229,94 @@ _skip_gtk_query() {
|
||||
[[ $output != *'[WARN]'* ]]
|
||||
[[ $output != *'ibus-gtk3'* ]]
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# _doctor_check_recent_crashes: GPU FATAL crash counter (#583)
|
||||
# =============================================================================
|
||||
|
||||
# Install a coredumpctl shim. $1 is the coredumpctl-list-style
|
||||
# multi-line output to emit (header + entry rows). The shim ignores
|
||||
# its arguments — tests don't exercise the filter syntax.
|
||||
_install_coredumpctl_shim() {
|
||||
mkdir -p "$TEST_TMP/bin"
|
||||
cat > "$TEST_TMP/bin/coredumpctl" <<SHIM
|
||||
#!/usr/bin/env bash
|
||||
cat <<'OUT'
|
||||
$1
|
||||
OUT
|
||||
SHIM
|
||||
chmod +x "$TEST_TMP/bin/coredumpctl"
|
||||
export PATH="$TEST_TMP/bin:$PATH"
|
||||
}
|
||||
|
||||
@test "_doctor_check_recent_crashes: no coredumpctl on PATH — silent" {
|
||||
# Force coredumpctl off PATH so the helper short-circuits.
|
||||
# Restore PATH before returning so teardown's rm works.
|
||||
local saved_path="$PATH"
|
||||
export PATH="/no-such-dir-for-test"
|
||||
run _doctor_check_recent_crashes \
|
||||
'/usr/lib/claude-desktop/node_modules/electron/dist/electron'
|
||||
export PATH="$saved_path"
|
||||
[[ $status -eq 0 ]]
|
||||
[[ -z $output ]]
|
||||
}
|
||||
|
||||
@test "_doctor_check_recent_crashes: zero crashes — silent" {
|
||||
# Listing has the header line only, no entry rows.
|
||||
_install_coredumpctl_shim 'TIME PID UID GID SIG COREFILE EXE SIZE'
|
||||
run _doctor_check_recent_crashes \
|
||||
'/usr/lib/claude-desktop/node_modules/electron/dist/electron'
|
||||
[[ $status -eq 0 ]]
|
||||
[[ -z $output ]]
|
||||
}
|
||||
|
||||
@test "_doctor_check_recent_crashes: 1 crash — info line, no warn" {
|
||||
_install_coredumpctl_shim 'TIME PID UID GID SIG COREFILE EXE SIZE
|
||||
Wed 2026-05-06 08:00:21 EDT 130375 1000 1000 SIGTRAP present /usr/lib/claude-desktop/node_modules/electron/dist/electron 21.6M'
|
||||
run _doctor_check_recent_crashes \
|
||||
'/usr/lib/claude-desktop/node_modules/electron/dist/electron'
|
||||
[[ $status -eq 0 ]]
|
||||
[[ $output == *'Recent Electron crashes: 1'* ]]
|
||||
[[ $output != *'[WARN]'* ]]
|
||||
}
|
||||
|
||||
@test "_doctor_check_recent_crashes: 3+ crashes — warn + #583 pointer" {
|
||||
_install_coredumpctl_shim 'TIME PID UID GID SIG COREFILE EXE SIZE
|
||||
Wed 2026-05-06 08:00:21 EDT 130375 1000 1000 SIGTRAP present /usr/lib/claude-desktop/node_modules/electron/dist/electron 21.6M
|
||||
Mon 2026-05-04 07:44:48 EDT 930532 1000 1000 SIGTRAP present /usr/lib/claude-desktop/node_modules/electron/dist/electron 22.8M
|
||||
Sun 2026-05-03 14:34:10 EDT 567221 1000 1000 SIGTRAP present /usr/lib/claude-desktop/node_modules/electron/dist/electron 12.4M'
|
||||
run _doctor_check_recent_crashes \
|
||||
'/usr/lib/claude-desktop/node_modules/electron/dist/electron'
|
||||
[[ $status -eq 0 ]]
|
||||
[[ $output == *'[WARN]'* ]]
|
||||
[[ $output == *'Recent Electron crashes: 3'* ]]
|
||||
[[ $output == *'CLAUDE_DISABLE_GPU=1'* ]]
|
||||
[[ $output == *'/issues/583'* ]]
|
||||
}
|
||||
|
||||
@test "_doctor_check_recent_crashes: path mismatch falls back with footnote" {
|
||||
# Three crashes from a DIFFERENT electron binary (e.g., Slack).
|
||||
# Caller passes claude-desktop's electron path, which doesn't
|
||||
# match — helper falls back to total count and adds the footnote
|
||||
# so the user knows the count may be cross-app.
|
||||
_install_coredumpctl_shim 'TIME PID UID GID SIG COREFILE EXE SIZE
|
||||
Wed 2026-05-06 09:00:00 EDT 200001 1000 1000 SIGSEGV present /usr/lib/slack/electron 30M
|
||||
Wed 2026-05-05 09:00:00 EDT 200002 1000 1000 SIGSEGV present /usr/lib/slack/electron 30M
|
||||
Wed 2026-05-04 09:00:00 EDT 200003 1000 1000 SIGSEGV present /usr/lib/slack/electron 30M'
|
||||
run _doctor_check_recent_crashes \
|
||||
'/usr/lib/claude-desktop/node_modules/electron/dist/electron'
|
||||
[[ $status -eq 0 ]]
|
||||
[[ $output == *'[WARN]'* ]]
|
||||
[[ $output == *'may be from other Electron apps'* ]]
|
||||
}
|
||||
|
||||
@test "_doctor_check_recent_crashes: empty electron_path falls back" {
|
||||
_install_coredumpctl_shim 'TIME PID UID GID SIG COREFILE EXE SIZE
|
||||
Wed 2026-05-06 08:00:21 EDT 130375 1000 1000 SIGTRAP present /usr/lib/claude-desktop/node_modules/electron/dist/electron 21.6M'
|
||||
# Caller didn't pass an electron_path — helper still counts and
|
||||
# emits the info line based on the unfiltered total.
|
||||
run _doctor_check_recent_crashes ''
|
||||
[[ $status -eq 0 ]]
|
||||
[[ $output == *'Recent Electron crashes: 1'* ]]
|
||||
[[ $output == *'may be from other Electron apps'* ]]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user