{"record":{"id":"6b3e15c4fe89e700","repo":"mastra-ai/mastra","slug":"factory-kickoff-run-was-aborted-before-it-finished","errorCode":null,"errorMessage":"Factory kickoff run was aborted before it finished.","messagePattern":"Factory kickoff run was aborted before it finished\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"mastracode/factory/src/rules/dispatcher.ts","lineNumber":1000,"sourceCode":"                throw new Error('Factory kickoff is waiting on a run that has not ended.');\n              }\n              armAgentEnd();\n              settled = await sendKickoff(`factory-kickoff:${record.kickoffKey}:retry:${record.attempts}`);\n              if (settled?.action !== 'wake') {\n                throw new Error('Factory kickoff was queued onto an ending run and never reached the agent.');\n              }\n            }\n            const observed = await waitForAgentEndOrTimeout(agentEnd, this.#skillCompletionObservationTimeoutMs);\n            if (!observed) {\n              throw new Error('Factory kickoff run terminal event was not observed before timeout.');\n            } else if (endReason === 'error') {\n              throw new Error('Factory kickoff run ended in error.');\n            } else if (endReason === 'aborted') {\n              // Retryable for the same reason as skill decisions: the dominant\n              // cause is the process going away underneath the run, not a\n              // deliberate stop, and a spurious retry is bounded by\n              // MAX_ATTEMPTS while a dead card costs a human a manual nudge.\n              throw new Error('Factory kickoff run was aborted before it finished.');\n            }\n          } finally {\n            unsubscribe();\n          }\n        },\n      );\n      const completed = await this.#storage.completePendingStart(leaseIdentity(record, this.#ownerId), new Date());\n      if (!completed) throw new Error('Factory kickoff lease was lost before completion.');\n    } catch (error) {\n      await this.#storage.failPendingStart({\n        ...leaseIdentity(record, this.#ownerId),\n        now: new Date(),\n        availableAt: retryAt(now, record.attempts),\n        lastError: sanitizeDispatchError(error),\n        failureCode: factoryDispatchFailureCode(error),\n        terminal: record.attempts >= MAX_ATTEMPTS,\n      });\n    }","sourceCodeStart":982,"sourceCodeEnd":1018,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/dispatcher.ts#L982-L1018","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await dispatcher.dispatch(record);\n} catch (e) {\n  if (String(e?.message).includes('was aborted')) {\n    await scheduleRetry(record); // safe: bounded by MAX_ATTEMPTS; aborts are usually process death\n  } else throw e;\n}","preventionTips":["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"],"tags":["factory","abort","lifecycle","retry"],"backgroundTag":"agent-run-aborted","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}