mastra-ai/mastra · warning
Factory kickoff run was aborted before it finished.
Error message
Factory kickoff run was aborted before it finished.
What it means
The kickoff run's terminal event reported endReason === 'aborted', i.e. the run was stopped before finishing. The comment notes this is deliberately retryable: the dominant cause is the process going away underneath the run (restart/crash) rather than a deliberate user stop, and spurious retries are bounded by MAX_ATTEMPTS, so a dead Factory card costs a human a manual nudge.
Source
Thrown at mastracode/factory/src/rules/dispatcher.ts:1000
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();
}
},
);
const completed = await this.#storage.completePendingStart(leaseIdentity(record, this.#ownerId), new Date());
if (!completed) throw new Error('Factory kickoff lease was lost before completion.');
} catch (error) {
await this.#storage.failPendingStart({
...leaseIdentity(record, this.#ownerId),
now: new Date(),
availableAt: retryAt(now, record.attempts),
lastError: sanitizeDispatchError(error),
failureCode: factoryDispatchFailureCode(error),
terminal: record.attempts >= MAX_ATTEMPTS,
});
}View on GitHub (pinned to 75dd419e61)
Solutions
- Check whether the abort was user-initiated; if so, re-arm the card manually or filter deliberate aborts from retry semantics.
- Ensure graceful shutdown drains in-flight runs (drain before exit) so deploys don't abort active kickoffs.
- Rely on the bounded retry (MAX_ATTEMPTS); if aborts are frequent from infra, add pre-stop hooks/termination grace periods.
- Investigate crash/OOM logs if aborts cluster with restarts.
Defensive patterns
Strategy: retry
Try / catch
try {
await dispatcher.dispatch(record);
} catch (e) {
if (String(e?.message).includes('was aborted')) {
await scheduleRetry(record); // safe: bounded by MAX_ATTEMPTS; aborts are usually process death
} else throw e;
} Prevention
- Add graceful shutdown draining so deploys don't abort in-flight runs
- Use pre-stop hooks and adequate termination grace periods in containers
- Distinguish user-initiated stops from infra aborts before requeueing
- Investigate OOM/crash logs if aborts correlate with restarts
When it happens
Trigger: The run ended with endReason === 'aborted' — process shutdown/crash during the run, an explicit abort/cancel call reaching the agent, or infrastructure teardown (deploy, scale-in) killing the run.
Common situations: Deployments or autoscaling terminating the server mid-run; SIGTERM/SIGINT to the process during active runs; a user pressing stop in the UI; container OOM kills.
Related errors
- Factory kickoff run ended in error.
- Factory storage domain '${this.name}' is already bound to an
- The operation was aborted.
- MastraAuthBetterAuth is not initialized — init() must run fi
- Shared browser not launched. Call createSharedSession() firs
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/6b3e15c4fe89e700.
Report an issue: GitHub.