Skip to content

Bug: Cron fallback chain broken — models return zero-token success or killed by shared AbortController #97115

Description

@tbertran

Bug: Cron fallback chain broken — models return zero-token "success" or are killed by shared AbortController

Summary

Isolated cron agentTurn jobs fail in a cascading way: the primary model times out, the fallback chain either dies instantly (shared AbortController from #37505) or a fallback model "responds" with 0 input tokens, 0 output tokens, and a clean stopReason: "stop" — which the harness treats as success, so no further fallback triggers. The 0-token model then gets permanently cached in sessions.json (#61573), poisoning subsequent runs.

Net result: cron fallback chains are non-functional. Jobs that should recover just fail silently.

Evidence

Cron jobs using model fallback chains produce zero-token calls when they reach a provider outside the OpenRouter/Codex families (observed with Google Gemini). Example pattern from a production usage.db:

2026-06-26 06:01 | google | gemini-3.5-flash | 0 in | 0 out | $0.00
2026-06-26 06:00 | google | gemini-3.5-flash | 0 in | 0 out | $0.00
2026-06-26 03:01 | google | gemini-3.5-flash | 0 in | 0 out | $0.00
2026-06-26 03:00 | google | gemini-3.5-flash | 0 in | 0 out | $0.00

Every call connects, returns stopReason: "stop", zero tokens, zero cost. The harness reports "Agent couldn't generate a response" — but treats it as a completed call, not an error, so no further fallback is attempted.

Related closed issues (same underlying bug, not resolved)

  1. Cron job timeout aborts entire model fallback chain via shared AbortController #37505 — "Cron job timeout aborts entire model fallback chain via shared AbortController" — stale-closed by barnacle bot, not fixed. Several PRs cross-referenced it but the issue was auto-closed without resolution.

  2. [Bug]: OpenRouter text-inference models return silent empty responses through cron-agent-turn harness in OpenClaw 2026.4.14 #67646 — "OpenRouter text-inference models return silent empty responses through cron-agent-turn harness" — closed as fixed, but the fix was OpenRouter-specific (base URL merge). The same "silent empty response" pattern now manifests on non-OpenRouter providers (e.g., Google Gemini).

  3. Cron sessions permanently cache fallback model in sessions.json #61573 — "Cron sessions permanently cache fallback model in sessions.json" — closed as fixed, but the cache poisoning persists when the fallback model is reached via the zero-token path.

Root cause hypothesis

Two overlapping bugs in the cron harness:

A) The cron runner (executeJobCoreWithTimeout) creates a single AbortController shared across the entire fallback chain. When primary model times out, the signal is already aborted — every subsequent fallback gets a dead signal, failing instantly without making a network request. (#37505)

B) When a fallback model does manage to fire, certain providers return a clean-looking response with 0 tokens — the harness doesn't classify this as a failure, so runWithModelFallback stops iterating. The job then fails with "Agent couldn't generate a response" instead of trying the next fallback.

This affects any provider that layers on top of the cron-agent-turn harness beyond the OpenRouter/Codex families.

Steps to reproduce

  1. Configure an agent with a model fallback chain that includes a non-OpenRouter provider (e.g., deepseek-v4-pro → minimax → google/gemini-flash)
  2. Create an isolated cron agentTurn job on that agent with a short timeout
  3. Wait for the primary model to time out or hit rate limits
  4. Observe: fallback models either die instantly (shared AbortController) or return 0-token "success" responses
  5. Check sessions.json — the 0-token model is now permanently cached for that cron session key

Environment

  • OpenClaw 2026.6.9
  • Linux x64
  • Node v25
  • Affected: all isolated cron agentTurn jobs with model chains reaching non-OpenRouter providers

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.no-staleExclude from stale automation

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions