◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/Cowork
◈ Cowork/2026-05-04Advanced

Why Cowork Scheduled Tasks Stop Mid-Run and How to Recover

Diagnose Cowork scheduled task failures using measured exit codes and real error output — why safe.directory delays failure instead of fixing it, how to pick a writable root before cloning, and how to structure logs with reason codes.

cowork16scheduled-taskautomation109troubleshooting92skill

✦ Premium Article

You set up an automation, and one morning you notice it stopped somewhere in the middle. If you have run Cowork scheduled tasks for any length of time, you know the feeling — and the harder part is that you often cannot tell why it stopped.

I run routine maintenance tasks as a solo developer, and over time a few clear patterns emerged. Here is how I organize them.

The second half of this article is not a tidy summary of theory. On the very day I wrote it, a scheduled run hit a working repository that had been left owned by another user and could not be written to. The exit codes and error strings below are the ones I captured in that session.

Why Scheduled Tasks "Disappear" Silently

The awkward part about scheduled tasks is that a failure does not always announce itself. A manual run shows you the problem on screen immediately. A scheduled run happens in the background, so a mid-run exit can go unnoticed for days.

The causes fall into three broad patterns.

Permission dialog lockups are the most common. Cowork scheduled tasks run when nobody is at the keyboard, so any confirmation dialog leaves the run waiting for an answer that never comes. AskUserQuestion, the Read / Write / Edit file tools, and request_cowork_directory all trigger dialogs. Use them in a scheduled context and the run stalls with nobody there to click "Allow."

Disk exhaustion (ENOSPC) shows up regularly in real operation. Anything that runs Claude Code or git clone on a schedule gradually eats /tmp. If npm package installation is in the loop, a single run can consume hundreds of megabytes.

Git lock conflicts happen when a previous run ended halfway. A leftover .git/index.lock makes the next run fail with fatal: Unable to create ... .git/index.lock.

These three are the manageable kind, because they surface as errors. The genuinely hard ones are the failures that produce no error at all and simply pretend to succeed. Those come later in the article.

Diagnosis: Identifying Which Pattern Hit You

Start with the run log. Cowork keeps a session log for scheduled tasks, so read the last message it emitted.

# Free space in /tmp (the ENOSPC signal)
df /tmp --output=avail -m | tail -1
 
# Leftover git lock files
find /tmp/repos -name "*.lock" 2>/dev/null
 
# Who owns the working root — and who are we?
stat -c '%U:%G %a %n' /tmp/repos/* 2>/dev/null
id -u

If the last log line lands right after an AskUserQuestion call or a Read tool invocation, it is a permission dialog. If you see ENOSPC or No space left on device, it is disk. If you see index.lock or fatal: Unable to create, it is a lock conflict.

The stat and id -u pairing at the end is deliberate. The uid your task runs as is not guaranteed to be stable, and a directory left behind by a previous process under a different user will fail every write from that point onward. The next section shows how nastily that surfaces.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Measured proof that safe.directory leaves git status at exit 0 while fetch alone fails with exit 255 — reads pass, so the failure surfaces minutes later than it should
✦A preflight that settles on a writable root before cloning (uid 65534 detection, $HOME fallback, free-space threshold), sized from measured numbers: 41MB per clone, 2.8s, 2,990MB free
✦Reason-coded logs attached to an EXIT trap — measured on bash 5.1.16, where a TERM handler that does not exit lets a killed run record itself as SUCCESS
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

◈ Cowork2026-09-08
Until I planted a failing sample, my unattended checks had never once failed
A check running on an unattended schedule lost its exit code to a single pipe added for readable logs. I measured where the status disappears and built a small harness that checks the checker.
◈ Cowork2026-08-23
Not Every Unreachable Connector Means the Same Thing in an Unattended Run
When an unattended task cannot reach a connector, the cause splits into three states: still connecting, unauthenticated, or genuinely absent. Each demands the opposite response. Here is the resolver that tells them apart.
◈ Cowork2026-10-08
The Night I Halved the Instructions I Load Every Time: Three Drawers Before Any Cutting
The longer an instruction file grows, the more rules slip through. Here is how I sorted what gets loaded every time into keep, move, and delete, plus a small script that measures each heading.