{"record":{"id":"a82d0c8a9c32d945","repo":"mastra-ai/mastra","slug":"work-item-is-required","errorCode":null,"errorMessage":"Work item is required","messagePattern":"Work item is required","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory-ui/src/hooks/useWorkItemComments.ts","lineNumber":28,"sourceCode":"  deleteWorkItemComment,\n  editWorkItemComment,\n  listWorkItemComments,\n} from '../ui/domains/factory/services/comments';\nimport type { CreateWorkItemCommentInput, EditWorkItemCommentInput } from '../ui/domains/factory/services/comments';\nimport type { WorkItemComment, WorkItemCommentPage } from '../ui/domains/factory/services/commentsWire';\n\nexport interface WorkItemFeedScope {\n  workItemId: string | undefined;\n  factoryProjectId: string | undefined;\n}\n\ntype CommentsData = InfiniteData<WorkItemCommentPage, string | undefined>;\n\n/** Invalidation refetches every loaded page serially, so keep the window bounded. */\nconst MAX_COMMENT_PAGES = 5;\n\nfunction requireWorkItemId(workItemId: string | undefined): string {\n  if (!workItemId) throw new Error('Work item is required');\n  return workItemId;\n}\n\nfunction createMutationKey(workItemId: string | undefined) {\n  return [...queryKeys.workItemCommentsRoot(workItemId), 'create'] as const;\n}\n\ntype CommentPatch = (comment: WorkItemComment) => WorkItemComment;\n\nfunction patchPage(page: WorkItemCommentPage, commentId: string, patch: CommentPatch): WorkItemCommentPage {\n  return {\n    ...page,\n    comments: page.comments.map(comment => (comment.id === commentId ? patch(comment) : comment)),\n  };\n}\n\n/** Every anchor the work item is read under holds its own pages; all of them carry the row. */\nfunction patchComments(queryClient: QueryClient, rootKey: QueryKey, commentId: string, patch: CommentPatch) {","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory-ui/src/hooks/useWorkItemComments.ts#L10-L46","documentation":"requireWorkItemId is a shared guard used by the create/edit/delete work-item comment mutations in useWorkItemComments.ts. Since workItemId is `string | undefined`, it throws 'Work item is required' when a comment operation is attempted without a work item id. This prevents comment requests from targeting an invalid URL (queryKeys.workItemCommentsRoot(undefined)).","triggerScenarios":"Calling create/edit/delete comment mutations while workItemId is undefined — e.g. the comments panel mounted before the selected work item resolved, selection was cleared while the panel stayed open, or the id prop was dropped during refactoring.","commonSituations":"Submitting the comment box after clicking a different board item that deselected the current one; deep-linked page where the work item query hasn't resolved; optimistic UI keeping the composer open for a deleted work item.","solutions":["Render the comments panel (and its composer) only when workItemId is defined.","Clear/close the composer when the selected work item changes or is removed.","Check the call site passes the resolved work item id (not an optional chained value) into the hooks."],"exampleFix":"// before\nconst { mutate: addComment } = useCreateWorkItemCommentMutation(workItemId);\n<CommentBox onSubmit={text => addComment({ text })} />\n\n// after\n{workItemId ? <CommentBox onSubmit={text => addComment({ text })} /> : null}","handlingStrategy":"validation","validationCode":"if (!workItemId) return null; // don't render comments panel","typeGuard":"const hasWorkItem = (id: string | undefined): id is string => typeof id === 'string' && id.length > 0;","tryCatchPattern":"addComment(payload, { onError: err => { if ((err as Error).message === 'Work item is required') closeComposer(); } });","preventionTips":["Mount comment hooks only when a work item is selected.","Close/clear the composer on work-item change or deletion.","Avoid optional chaining when passing ids into hooks; resolve first."],"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"}