{"record":{"id":"c7c8c5c719020e67","repo":"gastownhall/beads","slug":"w-add-comment-requires-an-issue-id","errorCode":null,"errorMessage":"%w: add comment requires an issue ID","messagePattern":"%w: add comment requires an issue ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/commenter.go","lineNumber":25,"sourceCode":"\t\"strings\"\n\n\t\"github.com/steveyegge/beads/internal/storage\"\n\tpublicops \"github.com/steveyegge/beads/issueops\"\n)\n\n// ValidateAddCommentRequest applies the request rules every Commenter\n// implementation shares.\n//\n// Blankness is decided on a TRIMMED copy and the request's own Text is left\n// alone: a comment of nothing but whitespace carries no information and is\n// almost always a shell quoting accident, but a comment that merely begins\n// with a newline is a comment.\nfunc ValidateAddCommentRequest(request publicops.AddCommentRequest) error {\n\tif request.Author == \"\" {\n\t\treturn fmt.Errorf(\"%w: add comment requires an author\", storage.ErrValidation)\n\t}\n\tif request.IssueID == \"\" {\n\t\treturn fmt.Errorf(\"%w: add comment requires an issue ID\", storage.ErrValidation)\n\t}\n\tif strings.TrimSpace(request.Text) == \"\" {\n\t\treturn fmt.Errorf(\"%w: comment text cannot be empty\", storage.ErrValidation)\n\t}\n\treturn nil\n}\n\n// AddCommentCommitMessage is the history entry a comment records. It is the\n// spelling both stores' own AddIssueComment already wrote.\nfunc AddCommentCommitMessage(issueID string) string {\n\treturn \"bd: comment \" + issueID\n}\n\n// ExecuteAddComment appends one comment in tx and reports the durable tables\n// changed. It is the store-backed body behind the Commenter accessor; the\n// unit-of-work provider has its own, for the reason Lifecycle does.\n//\n// A comment on an ephemeral row changes only wisp_comments, which","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/commenter.go#L7-L43","documentation":"ValidateAddCommentRequest rejects an AddCommentRequest with an empty IssueID. A comment must anchor to an existing issue or wisp row; with no ID there is nothing to attach to, so the request fails validation with wrapped storage.ErrValidation before any query runs.","triggerScenarios":"Calling AddComment with publicops.AddCommentRequest{Author: \"alice\", Text: \"note\"} and IssueID unset; computing the issue ID from a variable that failed to populate (empty CLI arg, failed lookup); marshalling a request from user input where the issue field was never filled.","commonSituations":"CLI tools that derive the issue ID from the current branch name or a positional arg and get an empty string; automation that loops over a list where one entry lacks an ID; API consumers omitting the issue_id key in a JSON body.","solutions":["Populate request.IssueID with the target issue's ID before calling AddComment.","Validate the ID is non-empty (and well-formed, e.g. has a prefix) at the call site and report which input was missing.","Classify with errors.Is(err, storage.ErrValidation) and reject the request upstream instead of retrying."],"exampleFix":"// before\nreq := publicops.AddCommentRequest{Author: author, Text: text}\n_ = store.AddComment(ctx, req) // fails: no issue ID\n\n// after\nif issueID == \"\" {\n\treturn fmt.Errorf(\"usage: bd comment <issue-id> <text>\")\n}\nreq := publicops.AddCommentRequest{IssueID: issueID, Author: author, Text: text}\nif err := store.AddComment(ctx, req); err != nil { return err }","handlingStrategy":"validation","validationCode":"if req.IssueID == \"\" {\n\treturn errors.New(\"issue ID is required to add a comment\")\n}","typeGuard":null,"tryCatchPattern":"if err := store.AddComment(ctx, req); err != nil {\n\tif errors.Is(err, storage.ErrValidation) {\n\t\treturn fmt.Errorf(\"invalid request (issue ID?): %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Validate CLI/args-derived issue IDs are non-empty before building the request.","Use a helper that refuses to build AddCommentRequest without both IssueID and Author.","In loops, skip-and-log entries lacking an ID rather than sending empty requests."],"tags":["validation","comments","go"],"backgroundTag":"missing-required-field","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}