{"record":{"id":"34d0e9e355a6db5f","repo":"mastra-ai/mastra","slug":"factory-run-requires-a-board-work-item","errorCode":null,"errorMessage":"Factory run requires a board work item","messagePattern":"Factory run requires a board work item","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory-ui/src/hooks/useStartFactoryRun.ts","lineNumber":94,"sourceCode":" * binding, board persistence, and kickoff delivery to the server coordinator.\n * The coordinator commits exact authority before it dispatches any message.\n *\n * The run is started in the background: the board stays put and a toast offers\n * the way into the thread once it exists.\n */\nexport function useStartFactoryRun() {\n  const { factoryId } = useParams<{ factoryId: string }>();\n  const factoryQuery = useFactoryQuery(factoryId);\n  const { baseUrl } = useApiConfig();\n  const navigate = useNavigate();\n  const queryClient = useQueryClient();\n  const repository = factoryQuery.data?.repositories[0];\n  const [phases, setPhases] = useState<Record<string, FactoryRunPhase>>({});\n\n  const mutation = useMutation({\n    mutationKey: factoryRunMutationKey(repository?.projectRepositoryId ?? '', factoryId),\n    mutationFn: async ({ branch, threadTitle, threadTags, invocation, workItem }: StartFactoryRunInput) => {\n      if (!factoryId || !workItem) throw new Error('Factory run requires a board work item');\n      if (!repository) throw new Error('Select a repository before starting a Factory run');\n      const phaseKey = runPhaseKey({ id: workItem.id, sourceKey: workItem.sourceKey, role: workItem.role });\n      const setPhase = (phase: FactoryRunPhase) => setPhases(current => ({ ...current, [phaseKey]: phase }));\n\n      setPhase('workspace');\n      const userSession = await createUserSession(baseUrl, repository.projectRepositoryId, { branch });\n      const sessionId = userSession.sessionId;\n      const desiredStage = workItem.stages.length === 1 ? workItem.stages[0] : undefined;\n      if (!isFactoryRuleStage(desiredStage)) throw new Error('Factory runs require one exclusive destination stage');\n\n      setPhase('kickoff');\n      const prepared = await startFactoryRun(baseUrl, factoryId, {\n        sessionId,\n        threadTitle,\n        threadTags,\n        kickoffKey: crypto.randomUUID(),\n        invocation:\n          invocation?.type === 'skill'","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory-ui/src/hooks/useStartFactoryRun.ts#L76-L112","documentation":"useStartFactoryRun's mutationFn validates its StartFactoryRunInput before creating a session and starting a run. It requires both a factoryId and a board workItem; if either is missing it throws 'Factory run requires a board work item'. A Factory run always originates from a board work item, so starting without one would produce an invalid kickoff payload to startFactoryRun.","triggerScenarios":"Calling start({ branch, threadTitle, threadTags, invocation }) without a workItem (or with factoryId falsy) — e.g. a 'Run' button outside the work-item context, or workItem state cleared by a board refresh while the click was in flight.","commonSituations":"Bulk/run-all UI invoking start for items whose workItem object failed to load; a refactor changed the work item prop name; starting a run from a page where factoryId is only set after selection and the user clicked early.","solutions":["Only call start() with a loaded workItem: disable the run action until workItem exists.","Verify factoryId is set before rendering the run controls (it participates in the same guard).","If the board refresh can null out workItem, capture/snapshot the workItem before initiating the run or re-fetch it in the mutation flow."],"exampleFix":"// before\nstart({ branch, invocation }); // workItem missing\n\n// after\nif (workItem) start({ branch, invocation, workItem });","handlingStrategy":"validation","validationCode":"const canStart = Boolean(factoryId && workItem);\nif (canStart) start({ branch, invocation, workItem });","typeGuard":"const isRunnableInput = (i: StartFactoryRunInput & { workItem?: WorkItem }): i is StartFactoryRunInput & { workItem: WorkItem } => Boolean(i.workItem);","tryCatchPattern":"try { await start(input); } catch (e) { if ((e as Error).message.includes('board work item')) openWorkItemPicker(); }","preventionTips":["Only expose run actions within a work-item context.","Disable the run button while workItem or factoryId is missing.","Re-validate workItem presence right before mutate to survive board refreshes."],"tags":["guard-clause","missing-parameter","factory-ui","react-query"],"backgroundTag":"missing-required-parameter","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}