claude-code - 💡(How to fix) Fix Desktop app: webview unresponsive handler kills renderer when app is backgrounded by macOS [1 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#48300Fetched 2026-04-16 07:03:40
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Participants
Timeline (top)
labeled ×1

Error Message

tj("Main webview became unresponsive", {level:"error", tags:{event:"webview-unresponsive"}}); 14:10:10 [error] Sentry caught: { value: 'Main webview became unresponsive' }

Root Cause

Found in app.asar → .vite/build/index.js. The "unresponsive" event handler on the main webview unconditionally kills the renderer:

t.on("unresponsive", async () => {
    $.info("Main webview is unresponsive, will kill and reload");
    tj("Main webview became unresponsive", {level:"error", tags:{event:"webview-unresponsive"}});
    U$++;
    t.forcefullyCrashRenderer();
    t.reload();
});

The problem: When the user switches to another app, macOS App Nap throttles/suspends the Electron renderer process. The main process detects the renderer as "unresponsive" (because it's napped, not because it's actually hung), and the handler immediately calls forcefullyCrashRenderer() + reload() — nuking the session.

Note: backgroundThrottling: false IS set in webPreferences, but this only controls Chromium's internal throttling of timers/rAF. It does not prevent macOS App Nap from suspending the entire renderer process.

Code Example

t.on("unresponsive", async () => {
    $.info("Main webview is unresponsive, will kill and reload");
    tj("Main webview became unresponsive", {level:"error", tags:{event:"webview-unresponsive"}});
    U$++;
    t.forcefullyCrashRenderer();
    t.reload();
});

---

14:09:52 [info] [SkillsPlugin] Window focused — polling now (last poll was 686855ms ago)
14:10:10 [info] Main webview is unresponsive, will kill and reload
14:10:10 [error] Sentry caught: { value: 'Main webview became unresponsive' }

14:28:49 [info] Main webview is unresponsive, will kill and reload
15:08:42 [info] Main webview is unresponsive, will kill and reload
15:14:21 [info] Main webview is unresponsive, will kill and reload
15:17:50 [info] Main webview is unresponsive, will kill and reload
15:22:35 [info] Main webview is unresponsive, will kill and reload
15:25:38 [info] Main webview is unresponsive, will kill and reload

---

t.on("unresponsive", async () => {
    // Don't kill the renderer if the window is backgrounded —
    // macOS App Nap likely just suspended it
    if (!t.isFocused() && !t.isVisible()) {
        $.info("Webview unresponsive but window is backgrounded, skipping kill");
        return;
    }
    // ...existing kill logic for genuinely hung renderers...
});
RAW_BUFFERClick to expand / collapse

Bug Description

The Claude desktop app goes blank/crashes when the user switches away from it for a few minutes and then returns. The user has to close and reopen the app to recover.

Root Cause

Found in app.asar → .vite/build/index.js. The "unresponsive" event handler on the main webview unconditionally kills the renderer:

t.on("unresponsive", async () => {
    $.info("Main webview is unresponsive, will kill and reload");
    tj("Main webview became unresponsive", {level:"error", tags:{event:"webview-unresponsive"}});
    U$++;
    t.forcefullyCrashRenderer();
    t.reload();
});

The problem: When the user switches to another app, macOS App Nap throttles/suspends the Electron renderer process. The main process detects the renderer as "unresponsive" (because it's napped, not because it's actually hung), and the handler immediately calls forcefullyCrashRenderer() + reload() — nuking the session.

Note: backgroundThrottling: false IS set in webPreferences, but this only controls Chromium's internal throttling of timers/rAF. It does not prevent macOS App Nap from suspending the entire renderer process.

Evidence from logs (~/Library/Logs/Claude/main.log)

7 crashes in a single session today (2026-04-15), all correlating with window focus changes:

14:09:52 [info] [SkillsPlugin] Window focused — polling now (last poll was 686855ms ago)
14:10:10 [info] Main webview is unresponsive, will kill and reload
14:10:10 [error] Sentry caught: { value: 'Main webview became unresponsive' }

14:28:49 [info] Main webview is unresponsive, will kill and reload
15:08:42 [info] Main webview is unresponsive, will kill and reload
15:14:21 [info] Main webview is unresponsive, will kill and reload
15:17:50 [info] Main webview is unresponsive, will kill and reload
15:22:35 [info] Main webview is unresponsive, will kill and reload
15:25:38 [info] Main webview is unresponsive, will kill and reload

The pattern is clear: user leaves → macOS naps the renderer → main process fires "unresponsive" → handler kills renderer → user returns to blank screen.

Suggested Fix

The "unresponsive" handler should:

  1. Check if the window is focused/visible before killing the renderer. If backgrounded, suppress the kill.
  2. Add a grace period: when the user returns (window gets focus), wait 5–10 seconds for the renderer to wake up before considering it truly unresponsive.
  3. Disable App Nap for the renderer process using Electron's app.commandLine.appendSwitch('disable-renderer-backgrounding') or the NSSupportsAutomaticTermination / NSAppSleepDisabled Info.plist keys.

Proposed pseudocode:

t.on("unresponsive", async () => {
    // Don't kill the renderer if the window is backgrounded —
    // macOS App Nap likely just suspended it
    if (!t.isFocused() && !t.isVisible()) {
        $.info("Webview unresponsive but window is backgrounded, skipping kill");
        return;
    }
    // ...existing kill logic for genuinely hung renderers...
});

Environment

  • Claude Desktop app (Electron)
  • macOS (Apple Silicon - MacBook Air)
  • Version: 2.1.38
  • Logs: ~/Library/Logs/Claude/main.log

Reproduction

  1. Open Claude desktop app
  2. Start a conversation / agent session
  3. Switch to another app for 2-5 minutes
  4. Switch back to Claude → screen is blank/white, session is gone

extent analysis

TL;DR

The issue can be fixed by modifying the "unresponsive" event handler to check if the window is focused/visible before killing the renderer and adding a grace period to wait for the renderer to wake up after the user returns.

Guidance

  • Check if the window is focused/visible before killing the renderer to prevent unnecessary restarts when the app is backgrounded.
  • Add a 5-10 second grace period after the user returns to the app to allow the renderer to wake up from App Nap before considering it unresponsive.
  • Consider disabling App Nap for the renderer process using Electron's app.commandLine.appendSwitch('disable-renderer-backgrounding') or the NSSupportsAutomaticTermination / NSAppSleepDisabled Info.plist keys.

Example

t.on("unresponsive", async () => {
    if (!t.isFocused() && !t.isVisible()) {
        $.info("Webview unresponsive but window is backgrounded, skipping kill");
        return;
    }
    // Wait for 5-10 seconds before killing the renderer
    await new Promise(resolve => setTimeout(resolve, 5000));
    // ...existing kill logic for genuinely hung renderers...
});

Notes

The proposed fix assumes that the isFocused() and isVisible() methods are available and accurate. Additionally, the grace period duration may need to be adjusted based on the specific requirements of the app.

Recommendation

Apply the workaround by modifying the "unresponsive" event handler to check the window focus and visibility, and add a grace period to wait for the renderer to wake up. This should prevent unnecessary restarts and allow the app to recover from App Nap.

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