{"record":{"id":"70313a411e4d2ea3","repo":"mastra-ai/mastra","slug":"factory-project-is-required-70313a","errorCode":null,"errorMessage":"Factory project is required","messagePattern":"Factory project is required","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory-ui/src/hooks/useFactoryDecisions.ts","lineNumber":30,"sourceCode":"export function useFactoryDecisionStatus(githubProjectId: string | undefined, statuses: FactoryDecisionStatus[]) {\n  const { baseUrl } = useApiConfig();\n  const statusKey = statuses.join(',');\n  return useQuery({\n    queryKey: queryKeys.factoryDecisions(githubProjectId, statusKey),\n    queryFn: () => fetchFactoryDecisions(baseUrl, githubProjectId!, { statuses, limit: 50 }),\n    enabled: Boolean(githubProjectId),\n    refetchInterval: 2_000,\n    staleTime: 1_000,\n  });\n}\n\n/** Release, turn down, or requeue one queued effect. */\nexport function useFactoryDecisionAction(githubProjectId: string | undefined, action: FactoryDecisionAction) {\n  const { baseUrl } = useApiConfig();\n  const queryClient = useQueryClient();\n  return useMutation({\n    mutationFn: (decisionId: string) => {\n      if (!githubProjectId) throw new Error('Factory project is required');\n      return actOnFactoryDecision(baseUrl, githubProjectId, decisionId, action);\n    },\n    onSuccess: async () => {\n      await Promise.all([\n        queryClient.invalidateQueries({ queryKey: queryKeys.factoryDecisionsRoot(githubProjectId) }),\n        queryClient.invalidateQueries({ queryKey: queryKeys.factoryAttentionRoot(githubProjectId) }),\n      ]);\n    },\n  });\n}\n\nexport function useFactoryDecisionHistory(\n  githubProjectId: string | undefined,\n  statusKey: string,\n  statuses: FactoryDecisionStatus[] | undefined,\n) {\n  const { baseUrl } = useApiConfig();\n  return useInfiniteQuery({","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory-ui/src/hooks/useFactoryDecisions.ts#L12-L48","documentation":"useFactoryDecisionAction wraps actOnFactoryDecision(baseUrl, githubProjectId, decisionId, action) to release, dismiss, or requeue a queued factory effect. Because githubProjectId is typed `string | undefined`, the mutationFn guards with 'Factory project is required' before issuing the request. The library throws rather than sending a malformed request to the decisions endpoint.","triggerScenarios":"Invoking any of retryDecision, approve, dismiss, retry, approveDecision, or dismissDecision while githubProjectId is undefined — e.g. the component mounted before the project selection resolved, or the id prop was dropped when wiring the hook.","commonSituations":"Decision list rendered from a query that hasn't resolved its parent project yet; a rename/refactor changed the prop so the hook now receives undefined; clicking an action button on a card before project context loads in a deeply nested route.","solutions":["Ensure the action buttons are disabled until githubProjectId is defined, or conditionally render the decision list only after the project resolves.","Verify the call site passes the correct variable (githubProjectId vs a similarly named project/factory id) into useFactoryDecisionAction.","If actions can legitimately occur without a project, restructure so the mutation is only created once the id exists (e.g. inside a child component mounted under a loaded route)."],"exampleFix":"// before\nconst { dismiss } = useFactoryDecisionAction(projectId, 'dismiss');\n<button onClick={() => dismiss(id)} />\n\n// after\nconst { dismiss } = useFactoryDecisionAction(projectId, 'dismiss');\n<button disabled={!projectId} onClick={() => projectId && dismiss(id)} />","handlingStrategy":"validation","validationCode":"if (!githubProjectId) return; // do not render or invoke decision actions","typeGuard":"const hasProject = (id: string | undefined): id is string => typeof id === 'string' && id.length > 0;","tryCatchPattern":"mutation.mutate(decisionId, { onError: err => { if ((err as Error).message === 'Factory project is required') showToast('Project not loaded yet'); } });","preventionTips":["Gate decision action buttons on githubProjectId presence.","Render decision lists only after the parent project query succeeds.","Keep prop names consistent (githubProjectId) to avoid wiring the wrong optional value."],"tags":["react-query","guard-clause","missing-parameter","factory-ui"],"backgroundTag":"missing-required-parameter","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}