gastownhall/beads · error
db: CommentSQLRepository.InsertRecord: comment must not be n
Error message
db: CommentSQLRepository.InsertRecord: comment must not be nil
What it means
InsertRecord validates its comment pointer before doing any SQL work. A nil *types.Comment means the caller has no record to insert, so the repository fails fast with this guard error rather than panicking on the subsequent struct dereference (copy := *comment). It is a pure programming/usage error, never a data or database problem.
Source
Thrown at internal/storage/domain/db/comment.go:130
}
return storage.NewSliceIter(bulk[issueID]), nil
}
func (r *commentSQLRepositoryImpl) Insert(ctx context.Context, issueID, author, text string, opts domain.CommentOpts) (*types.Comment, error) {
// Live add: advance past the issue's newest comment so a burst inside one
// second still reads back in write order (issueops.NextLiveCommentTime).
// InsertRecord honors a supplied CreatedAt verbatim, which is what keeps
// imported comments on their original timestamps.
stamp, err := issueops.NextLiveCommentTime(ctx, r.runner, pickCommentTable(opts.UseWispsTable), issueID, time.Now())
if err != nil {
return nil, fmt.Errorf("db: CommentSQLRepository.Insert: %w", err)
}
return r.InsertRecord(ctx, &types.Comment{IssueID: issueID, Author: author, Text: text, CreatedAt: stamp}, opts)
}
func (r *commentSQLRepositoryImpl) InsertRecord(ctx context.Context, comment *types.Comment, opts domain.CommentOpts) (*types.Comment, error) {
if comment == nil {
return nil, fmt.Errorf("db: CommentSQLRepository.InsertRecord: comment must not be nil")
}
copy := *comment
if copy.IssueID == "" {
return nil, fmt.Errorf("db: CommentSQLRepository.InsertRecord: issueID must not be empty")
}
issueTable := pickIssueTable(opts.UseWispsTable)
var exists bool
//nolint:gosec // G201: issueTable is one of two hardcoded constants
if err := r.runner.QueryRowContext(ctx,
fmt.Sprintf("SELECT EXISTS(SELECT 1 FROM %s WHERE id = ?)", issueTable), copy.IssueID).Scan(&exists); err != nil {
return nil, fmt.Errorf("db: CommentSQLRepository.InsertRecord: check issue existence: %w", err)
}
if !exists {
return nil, fmt.Errorf("db: CommentSQLRepository.InsertRecord: issue %s not found", copy.IssueID)
}
if copy.CreatedAt.IsZero() {View on GitHub (pinned to 71377f2769)
Solutions
- Ensure the *types.Comment is non-nil before calling InsertRecord (allocate with &types.Comment{...}).
- If wrapping Insert, build the record inside the wrapper as Insert does rather than forwarding a possibly-nil pointer.
- Check any caller that does if c != nil { InsertRecord(ctx, c, ...) } — invert the early-return so nil never reaches the call.
Example fix
// before
var c *types.Comment
repo.InsertRecord(ctx, c, opts) // guard error
// after
c := &types.Comment{IssueID: id, Author: author, Text: text}
repo.InsertRecord(ctx, c, opts) Defensive patterns
Strategy: validation
Validate before calling
func validateComment(c *types.Comment) error {
if c == nil {
return fmt.Errorf("comment must not be nil")
}
return nil
} Type guard
func commentIsNotNil(c *types.Comment) bool { return c != nil } Try / catch
if _, err := repo.InsertRecord(ctx, comment, opts); err != nil {
if strings.Contains(err.Error(), "comment must not be nil") {
// fix caller: allocate a non-nil *types.Comment before calling
}
} Prevention
- Never pass pointer variables that may hold nil; construct with &types.Comment{...} at the call site.
- Run staticcheck/golangci-lint nil-dereference checks to catch nil paths before they reach the repository.
- Write a table-driven unit test covering the nil-input guard.
When it happens
Trigger: Calling CommentSQLRepository.InsertRecord(ctx, nil, opts) directly, or a wrapper that returns nil on an error path but passes the nil result straight into InsertRecord.
Common situations: Code that unmarshals comments from JSON where the field was absent (yielding nil), refactorings where an earlier nil-check was removed, or tests exercising the guard.
Related errors
- db: CommentSQLRepository.InsertRecord: issueID must not be e
- no store is open for this workspace
- not found
- no absolute native user directory is available
- ExternalDoltConfig: set either Socket OR (Host, Port), not b
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/9b0fb06e7eb68fdb.
Report an issue: GitHub.