gastownhall/beads · error
check comment existence in %s: %w
Error message
check comment existence in %s: %w
What it means
InsertDerivedComment first probes for an existing identical comment row (content-derived dedup); this wraps any probe error other than sql.ErrNoRows. It means the existence-check SELECT (issue_id, author, text, created_at with NULL-safe comparison, ORDER BY id LIMIT 1) failed at the SQL level — schema mismatch, connection failure, or cancelled context.
Source
Thrown at internal/storage/issueops/derivedid.go:225
// InsertDerivedComment inserts a comment under its content-derived id, or
// collapses onto an existing identical comment: a same-content row already in
// table (any id — it may predate the derivation) is the same logical comment,
// and the import path has always existence-checked exactly this column set
// (issue_id, author, text, created_at) rather than insert a duplicate. It
// returns the surviving row's id and whether it already existed.
//
//nolint:gosec // G201: table is a hardcoded routing constant at every call site.
func InsertDerivedComment(ctx context.Context, tx DBTX, table, issueID, author, text, createdAt string) (id string, existed bool, err error) {
err = tx.QueryRowContext(ctx, fmt.Sprintf(`
SELECT id FROM %s
WHERE issue_id = ? AND author = ? AND text = ? AND created_at = ?
ORDER BY id LIMIT 1`, table),
issueID, author, text, createdAt).Scan(&id)
if err == nil {
return id, true, nil
}
if err != sql.ErrNoRows {
return "", false, fmt.Errorf("check comment existence in %s: %w", table, err)
}
digest := rowid.Digest([]sql.NullString{str(issueID), str(author), str(text), str(createdAt)})
id = rowid.New(table, 0, digest)
if _, err := tx.ExecContext(ctx, fmt.Sprintf(`
INSERT INTO %s (id, issue_id, author, text, created_at)
VALUES (?, ?, ?, ?, ?)`, table),
id, issueID, author, text, createdAt); err != nil {
return "", false, fmt.Errorf("add comment to %s: %w", table, err)
}
return id, false, nil
}
// InsertDerivedCompactionSnapshot inserts a compaction_snapshots row under
// its content-derived id, with the same ordinal discipline as events. Two
// clones compacting the same issue at the same tier in the same second
// produce byte-identical snapshots and therefore the same id.
func InsertDerivedCompactionSnapshot(ctx context.Context, tx DBTX, issueID string, level int, snapshotJSON []byte, createdAt string) error {
if createdAt == "" {View on GitHub (pinned to 71377f2769)
Solutions
- Apply schema migrations so the comments table matches the expected shape.
- Confirm the table constant routes to an existing derived comments table.
- Retry in a fresh transaction if the connection was aborted.
- Read the wrapped driver error (`errors.Unwrap` chain) for the precise SQL message.
Example fix
// before
if err != sql.ErrNoRows {
return "", false, fmt.Errorf("check comment existence in %s: %w", table, err)
}
// after: also handle context cancellation distinctly
if err != sql.ErrNoRows {
if ctx.Err() != nil { return "", false, ctx.Err() }
return "", false, fmt.Errorf("check comment existence in %s: %w", table, err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if err := ctx.Err(); err != nil { return err }
cols, err := tableColumns(tx, table)
if err != nil { return err }
for _, c := range []string{"id", "issue_id", "author", "text", "created_at"} {
if !slices.Contains(cols, c) {
return fmt.Errorf("%s missing %s; migrate first", table, c)
}
} Type guard
func isNonNoRowsQueryErr(err error) bool {
return err != nil && !errors.Is(err, sql.ErrNoRows)
} Try / catch
id, created, err := InsertDerivedComment(ctx, tx, table, issueID, author, text, createdAt)
if err != nil {
if errors.Is(err, context.Canceled) { return err }
if strings.Contains(err.Error(), "Unknown column") {
return fmt.Errorf("migrate comment schema: %w", err)
}
return err
} Prevention
- Ensure comment-table migrations ran before PersistComments imports.
- Don't reuse transactions after a failed statement; start fresh.
- Check ctx cancellation separately from SQL errors for clean diagnostics.
- Import comments sequentially per issue to avoid probe/insert races.
When it happens
Trigger: addIssueCommentInTx / PersistComments run against a comments table missing expected columns, a wrong table constant, or with a broken connection inside the transaction.
Common situations: Databases created before comment-table migrations; hand-edited schemas; Dolt connection dropped mid-transaction during import (PersistComments).
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- read newest comment time from %s: %w
- scan same-content events in %s: %w
- add comment to %s: %w
- load wisp comments: %w
- read comments for %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/d547c380a9320eef.
Report an issue: GitHub.