You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Trigger: cron job with payload.kind: "agentTurn", sessionTarget: "isolated", delivery.mode: "announce"
Model that produced the run:minimax/MiniMax-M3
Host: Linux 6.17.0, Node v24.16.0
Observed: every night 2026-06-19 through 2026-06-24, Asia/Shanghai 01:08 cron run
Summary
When an isolated cron agentTurn hits a non-fatal tool error mid-run (e.g. an exec call rejected for an unsupported shell redirect), and the agent recovers by retrying with a different successful action and then emits a final user-visible answer, the cron runner classifies the whole run as status: "error". As a result:
The success announce delivery is skipped entirely — the operator receives no report at all.
A failure notification is synthesized from the recovered tool error (⚠️ 🛠️ <command> failed).
From the operator's perspective the cron "failed every night", but the underlying task actually completed successfully and produced a full report — the report just never got delivered.
Observed evidence
Cron run log (cron_run_logs table):
2026-06-24 01:08 | status=error | error=⚠️ 🛠️ run query.sh xhs → show /tmp/xhs_query.json failed | delivered=0 | delivery_status=not-delivered
2026-06-23 01:08 | status=error | error=⚠️ 🛠️ list files in calibration/wx_mp/predictions/ … | delivered=0
2026-06-22 01:08 | status=error | error=⚠️ 🛠️ …python one-liner… | delivered=0
…(same shape every night since 06-19)
2026-06-18 01:08 | status=ok | delivered=1 ← last clean run (no tool error that night)
The 2026-06-24 session trajectory tells the real story:
The exec tool doesn't run a shell, so it rejected this with {"ok":false,"error":"unknown arg: >"}, exitCode: 1. The exec details carries no errorCode field — only exitCode + aggregated.
The agent immediately retried without the redirect (query.sh --platform xhs --limit 12) and succeeded, then completed all remaining steps (60+ further tool calls) and emitted a full final report as finalAssistantVisibleText.
The fatal classification happens in resolveCronPayloadOutcome (src/cron/isolated-agent/helpers.ts). With runLevelError undefined (session succeeded) and failureSignal undefined (the exec error has no errorCode, so resolveEmbeddedRunFailureSignal returns undefined), the run is fatal iff hasFatalStructuredErrorPayload:
The recovery gates fail to fire for a recovered exec error:
hasSuccessfulPayloadAfterLastError (:258) only counts deliverable successful payloads after the last error (isSuccessfulCronPayload → isDeliverablePayload → hasOutboundReplyContent). The agent's retry exec succeeds, but its stdout JSON is intermediate tool output, not deliverable, so it doesn't count.
The agent's final report lives in finalAssistantVisibleText, which is not in params.payloads and is not consulted by hasSuccessfulPayloadAfterLastError.
hasNonTerminalToolErrorWarning / hasPendingPresentationWarning / hasRecoveredToolWarning all require the last error payload to carry specific markers (nonTerminalToolErrorWarning metadata, a presentation-warning text shape, or a "tool warning" text classification). A plain exec error like unknown arg: > carries none of these markers, so none of the gates fire.
Net effect: a recovered tool error with a successful final answer is treated as fatal. Then in src/cron/isolated-agent/run.ts:1133:
if(hasFatalStructuredErrorPayload&&prepared.deliveryRequested){awaitcleanupDirectCronSession({...});returnresolveRunOutcome({...});// ← returns BEFORE dispatchCronDelivery}
the success announce is never dispatched (delivered=0), and a failure notification is built from the recovered tool error instead.
Suggested fix
The presence of a non-empty finalAssistantVisibleText (or any non-error tool payload after the last error) should constitute proof of recovery and downgrade hasFatalStructuredErrorPayload to false. Minimal change in resolveCronPayloadOutcome:
(Alternatively, broaden hasSuccessfulPayloadAfterLastError to count any payload.isError !== true payload after the last error, not only deliverable ones.)
This preserves the existing behavior for genuinely fatal runs (no final answer, run-level error, or fatalForCron failure signal) while letting a recovered run deliver its final report.
Impact
The operator receives no cron report for otherwise-successful runs (silent success, noisy failure).
Recurs nightly for any cron whose agent habitually probes with a shell-ism the exec tool rejects (>, 2>&1, ;, quoted python one-liners, etc.) and then retries — a common MiniMax/Claude recovery pattern.
Degrades trust in cron status: 6 consecutive nights of status=error that were all actually successful.
[Bug] Cron
agentTurnrun misclassified as fatal when agent recovers from a transient tool error — success announce suppressedEnvironment
844f405ac1be805d5c598922a37254f12ab6d765)payload.kind: "agentTurn",sessionTarget: "isolated",delivery.mode: "announce"minimax/MiniMax-M3Summary
When an isolated cron
agentTurnhits a non-fatal tool error mid-run (e.g. anexeccall rejected for an unsupported shell redirect), and the agent recovers by retrying with a different successful action and then emits a final user-visible answer, the cron runner classifies the whole run asstatus: "error". As a result:announcedelivery is skipped entirely — the operator receives no report at all.⚠️ 🛠️ <command> failed).From the operator's perspective the cron "failed every night", but the underlying task actually completed successfully and produced a full report — the report just never got delivered.
Observed evidence
Cron run log (
cron_run_logstable):The 2026-06-24 session trajectory tells the real story:
session.ended.data.finalStatus = "success",aborted/timedOut = falseexectool doesn't run a shell, so it rejected this with{"ok":false,"error":"unknown arg: >"},exitCode: 1. The execdetailscarries noerrorCodefield — onlyexitCode+aggregated.query.sh --platform xhs --limit 12) and succeeded, then completed all remaining steps (60+ further tool calls) and emitted a full final report asfinalAssistantVisibleText.trace.artifacts.data.lastToolErroris still populated by the recovered exec error at run end (see related [Bug] Gateway swallows user-visible reply when an agent's exec stdout matches "configuration file" — replies=2 puts ⚠️ 🛠️ first, the actual reply second #96239 for the samelastToolError/mutatingActionarea), but that is a separate symptom — see root cause below.Root cause
The fatal classification happens in
resolveCronPayloadOutcome(src/cron/isolated-agent/helpers.ts). WithrunLevelErrorundefined (session succeeded) andfailureSignalundefined (the exec error has noerrorCode, soresolveEmbeddedRunFailureSignalreturns undefined), the run is fatal iffhasFatalStructuredErrorPayload:The recovery gates fail to fire for a recovered exec error:
hasSuccessfulPayloadAfterLastError(:258) only counts deliverable successful payloads after the last error (isSuccessfulCronPayload→isDeliverablePayload→hasOutboundReplyContent). The agent's retry exec succeeds, but its stdout JSON is intermediate tool output, not deliverable, so it doesn't count.finalAssistantVisibleText, which is not inparams.payloadsand is not consulted byhasSuccessfulPayloadAfterLastError.hasNonTerminalToolErrorWarning/hasPendingPresentationWarning/hasRecoveredToolWarningall require the last error payload to carry specific markers (nonTerminalToolErrorWarningmetadata, a presentation-warning text shape, or a "tool warning" text classification). A plain exec error likeunknown arg: >carries none of these markers, so none of the gates fire.Net effect: a recovered tool error with a successful final answer is treated as fatal. Then in
src/cron/isolated-agent/run.ts:1133:the success announce is never dispatched (
delivered=0), and a failure notification is built from the recovered tool error instead.Suggested fix
The presence of a non-empty
finalAssistantVisibleText(or any non-error tool payload after the last error) should constitute proof of recovery and downgradehasFatalStructuredErrorPayloadto false. Minimal change inresolveCronPayloadOutcome:(Alternatively, broaden
hasSuccessfulPayloadAfterLastErrorto count anypayload.isError !== truepayload after the last error, not only deliverable ones.)This preserves the existing behavior for genuinely fatal runs (no final answer, run-level error, or
fatalForCronfailure signal) while letting a recovered run deliver its final report.Impact
exectool rejects (>,2>&1,;, quoted python one-liners, etc.) and then retries — a common MiniMax/Claude recovery pattern.status=errorthat were all actually successful.Related
trace.artifacts.lastToolError/mutatingActionarea surfacing a⚠️ 🛠️warning card in Feishu; this issue is the cron-fatal-classification sibling of that symptom.