claude-code - 💡(How to fix) Fix [scheduler] scheduled-task discarded on wake from macOS maintenance sleep — no catch-up / replay

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…

On macOS (Apple Silicon, laptop), a scheduled task whose dispatch window falls inside a maintenance-sleep cycle is silently discarded on wake rather than replayed. The combination of (a) Claude Code's PreventUserIdleSystemSleep assertion not being strong enough to block maintenance sleep, and (b) the scheduler's hard-expiry semantics, means routine automation can silently fail on any laptop with default power settings.

Today's miss cost ~40 minutes (I manually fired "run now" after noticing "skipped" in the routines page). On a different day with no human-in-the-loop, the morning briefing would simply not exist.

Error Message

  • Beyond the grace period, log a skip with the reason (sleep vs error

Root Cause

Modern Macs default to aggressive maintenance-sleep behaviour. Any user running scheduled automation on a laptop is exposed — the failure is silent (skip logged, no notification) and structural (will recur until mitigated). Daily automation that the user relies on to surface inbox items, briefings, or status updates can fail open without warning.

Fix Action

Fix / Workaround

On macOS (Apple Silicon, laptop), a scheduled task whose dispatch window falls inside a maintenance-sleep cycle is silently discarded on wake rather than replayed. The combination of (a) Claude Code's PreventUserIdleSystemSleep assertion not being strong enough to block maintenance sleep, and (b) the scheduler's hard-expiry semantics, means routine automation can silently fail on any laptop with default power settings.

Time (BST)Event
07:00:14Scheduler logs the task as due, applies 463s jitter → planned dispatch ~07:07:43
07:01:31macOS enters maintenance sleep: Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active Using AC (Charge:79%)
07:07:43Planned dispatch time — machine is asleep
07:17:07macOS dark-wakes. Claude scheduler logs Cleared stale pending dispatch for: morning-briefing
07:43I notice "skipped" on routines page, manually click "run now" → succeeds

2. Scheduler discards delayed dispatch instead of replaying it on wake. Even with the weaker assertion, a robust laptop-aware scheduler would notice on wake that a dispatch window was missed and execute the job immediately (misfire-grace-period / catch-up semantics — see cron's @reboot, systemd timers' Persistent=true, anacron, etc.). Claude Code's scheduler does the opposite: explicitly clears the stale dispatch on wake.

RAW_BUFFERClick to expand / collapse

Summary

On macOS (Apple Silicon, laptop), a scheduled task whose dispatch window falls inside a maintenance-sleep cycle is silently discarded on wake rather than replayed. The combination of (a) Claude Code's PreventUserIdleSystemSleep assertion not being strong enough to block maintenance sleep, and (b) the scheduler's hard-expiry semantics, means routine automation can silently fail on any laptop with default power settings.

Today's miss cost ~40 minutes (I manually fired "run now" after noticing "skipped" in the routines page). On a different day with no human-in-the-loop, the morning briefing would simply not exist.

Environment

  • Claude Code: 2.1.143
  • macOS: 26.4.1 (build 25E253), arm64 (Apple Silicon)
  • Power settings (default-ish): standby 1, powernap 1, tcpkeepalive on, on AC the whole time
  • Task: a custom morning-briefing scheduled task (~/.claude/scheduled-tasks/morning-briefing/SKILL.md), scheduled daily at 07:00

Timeline (2026-05-18)

Time (BST)Event
07:00:14Scheduler logs the task as due, applies 463s jitter → planned dispatch ~07:07:43
07:01:31macOS enters maintenance sleep: Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active Using AC (Charge:79%)
07:07:43Planned dispatch time — machine is asleep
07:17:07macOS dark-wakes. Claude scheduler logs Cleared stale pending dispatch for: morning-briefing
07:43I notice "skipped" on routines page, manually click "run now" → succeeds

Evidence: ~/Library/Logs/Claude/main.log (scheduler trace), pmset -g log (sleep/wake transitions), pmset -g assertions (assertion type held).

Root cause (two-part)

1. Sleep assertion is too weak. pmset -g shows sleep prevented by powerd, Claude. This is a PreventUserIdleSystemSleep assertion — it blocks user-idle sleep, but does NOT prevent powerd from entering maintenance sleep. On Apple Silicon, maintenance sleep can happen even on AC with the lid open.

The right assertion for a process that needs to fire jobs reliably while the machine is unattended is PreventSystemSleep (held by caffeinate -s and equivalents).

2. Scheduler discards delayed dispatch instead of replaying it on wake. Even with the weaker assertion, a robust laptop-aware scheduler would notice on wake that a dispatch window was missed and execute the job immediately (misfire-grace-period / catch-up semantics — see cron's @reboot, systemd timers' Persistent=true, anacron, etc.). Claude Code's scheduler does the opposite: explicitly clears the stale dispatch on wake.

Proposed fix (scheduler-side, preferred)

Add wake-replay / catch-up semantics. On wake, for any task whose dispatch window expired during sleep:

  • Within a configurable grace period (default e.g. 30 minutes), execute the job immediately and log it as a delayed dispatch.
  • Beyond the grace period, log a skip with the reason (sleep vs error vs overlap) so the routines UI can distinguish them.

This makes Claude Code's scheduled tasks reliable on laptops without forcing users to wrap the launcher in caffeinate or globally disable maintenance sleep.

Workaround for current users

Wrap whatever launches Claude Code with caffeinate -dimsu so it holds PreventSystemSleep. Verify with pmset -g assertions — should list PreventSystemSleep, not just PreventUserIdleSystemSleep. Caveats: affects battery on portable use; doesn't fix the scheduler-side fragility, only the specific maintenance-sleep trigger.

Why this matters

Modern Macs default to aggressive maintenance-sleep behaviour. Any user running scheduled automation on a laptop is exposed — the failure is silent (skip logged, no notification) and structural (will recur until mitigated). Daily automation that the user relies on to surface inbox items, briefings, or status updates can fail open without warning.

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 [scheduler] scheduled-task discarded on wake from macOS maintenance sleep — no catch-up / replay