[Bug] Sleep inhibitor rotation creates gap allowing system sleep during active tasks
Bug Description
Bug: macOS sleep inhibitor rotation briefly drops all sleep assertions and allows system sleep during active Claude Code tasks
Summary
Claude Code appears to restart its macOS caffeinate sleep inhibitor every ~4 minutes by stopping the existing inhibitor before starting the replacement.
When the display is off and the machine is otherwise idle, this creates a brief interval with no PreventUserIdleSystemSleep assertion. macOS can begin idle sleep during that interval before the replacement caffeinate assertion takes effect.
This caused an active Claude Code implementation task to suspend for approximately 4 minutes until keyboard/trackpad activity woke the Mac.
Environment
- macOS
- MacBook Air
- Claude Code 2.1.226
- Running on battery
- Laptop open
- Display had turned off due to inactivity
- Battery was approximately 14%
Reproduction observed
Claude Code periodically logs:
15:24:30.537 Restarting sleep inhibitor to maintain prevention
15:24:30.537 Stopped sleep inhibitor, allowing sleep
15:24:30.539 Started caffeinate to prevent sleep
15:28:30.542 Restarting sleep inhibitor to maintain prevention
15:28:30.542 Stopped sleep inhibitor, allowing sleep
15:28:30.552 Started caffeinate to prevent sleep
At the second rotation, macOS logged:
11:28:30.581 caffeinate.69856 ClientDied PreventUserIdleSystemSleep
[System: No Assertions]
11:28:30.590 Received kIOMessageCanSystemSleep
11:28:30.614 Received kIOMessageSystemWillSleep
A replacement caffeinate process appeared immediately afterward, but macOS had already begun the sleep transition.
A few seconds later:
11:28:35 Entering Sleep state due to 'Idle Sleep'
The machine later entered Maintenance Sleep and remained asleep until user input:
11:32:55 Wake from Deep Idle ... trackpadkeyboard ... UserActivity
Claude Code then detected:
[byte-watchdog] ... slept=249630ms (sleep/suspend)
Stream connection error (StreamSuspended) — retrying streaming
Expected behavior
An active Claude Code task should continuously hold a sleep-prevention assertion.
If the sleep inhibitor must be periodically replaced, the replacement should acquire its assertion before the previous inhibitor is terminated, so there is never a gap with zero sleep-prevention assertions.
For example:
- Start replacement inhibitor.
- Verify replacement assertion is active.
- Terminate old inhibitor.
Alternatively, keep a single caffeinate process alive for the duration of the active task.
Actual behavior
Claude Code appears to:
- Stop the existing inhibitor.
- Start a new inhibitor.
During this transition macOS briefly reports:
[System: No Assertions]
and can immediately initiate idle system sleep.
Impact
Long-running Claude Code tasks can silently stop executing when the display turns off. From the user's perspective Claude appears to hang indefinitely, then suddenly resumes when the keyboard or trackpad is touched.
In this occurrence, approximately four minutes of an active coding task were lost to system sleep.
Environment Info
- Platform: darwin
- Terminal: Apple_Terminal
- Version: 2.1.226
- Feedback ID: 51290b07-cb96-489a-8e58-7aaaf9b7baa3
Errors
[]This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗