{"record":{"id":"416885b0c2c505df","repo":"gastownhall/beads","slug":"w-add-comment-requires-an-author","errorCode":null,"errorMessage":"%w: add comment requires an author","messagePattern":"%w: add comment requires an author","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/commenter.go","lineNumber":22,"sourceCode":"\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\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","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/commenter.go#L4-L40","documentation":"ValidateAddCommentRequest rejects an AddCommentRequest whose Author field is the empty string. Beads records who wrote every comment, and an anonymous comment cannot be attributed in history or rendered, so the request is refused before any database work with a wrapped storage.ErrValidation sentinel. Fix the request, not the store.","triggerScenarios":"Calling AddComment (or ExecuteAddComment via any Commenter) with publicops.AddCommentRequest{IssueID: \"bd-1\", Text: \"hi\"} and Author left unset; building the request struct by field name and forgetting Author; deserializing a JSON payload that omits the author field.","commonSituations":"Scripts that construct AddCommentRequest programmatically after reading an author from config or env (BD_USER, git config user.email) and hit an unset variable; API wrappers that map an incoming payload with a missing/empty author field; tests that reuse a partially-filled request struct.","solutions":["Set request.Author to a non-empty identifier (username or email) before calling AddComment.","If the author comes from an env var or config, check it is non-empty at startup and fail early with a clear message.","Use errors.Is(err, storage.ErrValidation) to classify this refusal and surface it as a 400-style error rather than an internal failure."],"exampleFix":"// before\nreq := publicops.AddCommentRequest{IssueID: issueID, Text: text}\nerr := store.AddComment(ctx, req)\n\n// after\nauthor := os.Getenv(\"BD_USER\")\nif author == \"\" {\n\treturn fmt.Errorf(\"BD_USER must be set to comment\")\n}\nreq := publicops.AddCommentRequest{IssueID: issueID, Author: author, Text: text}\nerr := store.AddComment(ctx, req)","handlingStrategy":"validation","validationCode":"func validCommentRequest(r publicops.AddCommentRequest) error {\n\tif r.Author == \"\" { return errors.New(\"author required\") }\n\tif r.IssueID == \"\" { return errors.New(\"issue ID required\") }\n\tif strings.TrimSpace(r.Text) == \"\" { return errors.New(\"comment text required\") }\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := store.AddComment(ctx, req); err != nil {\n\tif errors.Is(err, storage.ErrValidation) {\n\t\treturn fmt.Errorf(\"bad comment request: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Centralize request construction in one constructor that fills Author from a resolved identity (env/config/git user).","Fail fast at startup when the author source (env var, config) is empty.","Reuse ValidateAddCommentRequest itself in tests and pre-flight checks."],"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"}