mastra-ai/mastra · error
Factory kickoff was queued onto an ending run and never reac
Error message
Factory kickoff was queued onto an ending run and never reached the agent.
What it means
During a kick-off retry against an in-flight run, the dispatcher queued the kickoff message onto the run as it was ending. sendKickoff returns a settled result whose action must be 'wake' to prove the message reached the agent; any other action (or no result) means the kickoff was swallowed by a terminating run and the card would strand. The library throws so the record is retried with a fresh dedupe-safe kickoff key.
Source
Thrown at mastracode/factory/src/rules/dispatcher.ts:987
);
try {
let settled = await sendKickoff(`factory-kickoff:${record.kickoffKey}`);
if (settled?.action === 'deliver') {
// `deliver` only proves the signal was queued onto a run already
// in flight. If that run ends without draining its queue the
// kickoff is dropped silently. There is no per-notification
// "processed" signal, so wait for the in-flight run to end and
// redeliver into the idle session unconditionally — the
// generation-scoped dedupeKey defeats inbox dedupe and the
// kickoff key keeps a duplicate run bounded, while a dropped
// kickoff strands the card forever.
if (!(await waitForAgentEndOrTimeout(agentEnd, this.#skillCompletionObservationTimeoutMs))) {
throw new Error('Factory kickoff is waiting on a run that has not ended.');
}
armAgentEnd();
settled = await sendKickoff(`factory-kickoff:${record.kickoffKey}:retry:${record.attempts}`);
if (settled?.action !== 'wake') {
throw new Error('Factory kickoff was queued onto an ending run and never reached the agent.');
}
}
const observed = await waitForAgentEndOrTimeout(agentEnd, this.#skillCompletionObservationTimeoutMs);
if (!observed) {
throw new Error('Factory kickoff run terminal event was not observed before timeout.');
} else if (endReason === 'error') {
throw new Error('Factory kickoff run ended in error.');
} else if (endReason === 'aborted') {
// Retryable for the same reason as skill decisions: the dominant
// cause is the process going away underneath the run, not a
// deliberate stop, and a spurious retry is bounded by
// MAX_ATTEMPTS while a dead card costs a human a manual nudge.
throw new Error('Factory kickoff run was aborted before it finished.');
}
} finally {
unsubscribe();
}
},View on GitHub (pinned to 75dd419e61)
Solutions
- Rely on the built-in retry: the throw marks the pending start failed with a retryAt schedule; ensure MAX_ATTEMPTS is not exhausted.
- Verify the inbox/dedupe layer is not swallowing retried kickoffs (each retry uses ':retry:<attempts>' in the key — check the key is unique).
- Check agent/session logs for the run's end event timing; if teardown routinely races delivery, serialize kickoff after confirmed run end.
- Ensure the agent process is stable (no crashes mid-run) — process restarts are the dominant cause per the surrounding code.
Defensive patterns
Strategy: retry
Try / catch
try {
await dispatcher.dispatch(record);
} catch (e) {
if (String(e?.message).includes('never reached the agent')) {
await scheduleRetry(record); // bounded by MAX_ATTEMPTS; kickoff key is attempt-suffixed
} else throw e;
} Prevention
- Keep MAX_ATTEMPTS and retry backoff configured so transient delivery races self-heal
- Don't bypass the generation-scoped dedupeKey mechanism with hand-rolled keys
- Ensure the agent process drains gracefully so runs don't terminate mid-delivery
- Watch for inbox dedupe suppressing retried kickoffs in logs
When it happens
Trigger: sendKickoff resolved with settled.action !== 'wake' — the run terminated between armAgentEnd() and delivery, the inbox rejected the message via dedupe, or the delivery landed after the agent stopped accepting input.
Common situations: Race between run teardown and message delivery under load; duplicate kickoff messages where generation-scoped dedupeKey suppressed a retry delivery; process crash mid-delivery; attempting wake on a run that already emitted its end event.
Related errors
- Factory kickoff is waiting on a run that has not ended.
- GitHub token refresh no longer matches the active Factory wo
- Factory workspace GitHub credential registration is no longe
- Factory session ${session.sessionId} was retired during work
- MastraAuthBetterAuth is not initialized — init() must run fi
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/d7cf7cdf32c9cda2.
Report an issue: GitHub.