gastownhall/beads · error

db: CommentSQLRepository.InsertRecord: check issue existence

Error message

db: CommentSQLRepository.InsertRecord: check issue existence: %w

What it means

Before inserting, InsertRecord runs SELECT EXISTS(...) against the issue table (issues or issues_wisps, per CommentOpts.UseWispsTable) to verify the parent issue exists. This error wraps any failure of that probe query itself — connection loss, SQL syntax/permission errors, a missing table, or a cancelled context — not the case of the issue being absent (that is a separate error).

Source

Thrown at internal/storage/domain/db/comment.go:142

	}
	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() {
		copy.CreatedAt = time.Now().UTC()
	} else {
		copy.CreatedAt = copy.CreatedAt.UTC()
	}
	createdAtText := issueops.FormatAuxTime(copy.CreatedAt)
	commentTable := pickCommentTable(opts.UseWispsTable)
	if copy.ID == "" {
		id, _, err := issueops.InsertDerivedComment(ctx, r.runner, commentTable, copy.IssueID, copy.Author, copy.Text, createdAtText)
		if err != nil {
			return nil, fmt.Errorf("db: CommentSQLRepository.InsertRecord: %w", err)
		}
		copy.ID = id

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause (%w) — it names the real SQL failure.
  2. Run schema migration/doctor so the chosen issue table (issues vs issues_wisps) exists.
  3. Verify opts.UseWispsTable matches the database generation you are actually connected to.
  4. Check DB connectivity and permissions, then retry; confirm the context isn't already cancelled.

Example fix

// before
repo.InsertRecord(ctx, c, domain.CommentOpts{UseWispsTable: true}) // old DB lacks issues_wisps
// after
opts := domain.CommentOpts{UseWispsTable: schemaSupportsWisps(db)}
repo.InsertRecord(ctx, c, opts)
Defensive patterns

Strategy: try-catch

Validate before calling

// check connectivity and schema before calling
if err := runner.PingContext(ctx); err != nil {
    return fmt.Errorf("database unavailable: %w", err)
}

Type guard

null

Try / catch

if _, err := repo.InsertRecord(ctx, c, opts); err != nil {
    if strings.Contains(err.Error(), "check issue existence") {
        cause := errors.Unwrap(err)
        // driver-level failure: inspect cause, verify schema (issues/issues_wisps)
        // and connectivity, then retry with backoff
    }
}

Prevention

When it happens

Trigger: The QueryRowContext(...).Scan(&exists) call returns a non-sql.ErrNoRows error: DB closed/misbehaving, the issue table (issues or issues_wisps) does not exist in this database, schema drift, permission denied on SELECT, or ctx cancelled mid-query.

Common situations: Pointing bd at a legacy or partially-migrated database where issues_wisps does not exist yet; a locked or crashed Dolt/SQLite file; network drop to a remote Dolt server; passing UseWispsTable: true against an old schema.

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/00f58625a620655a. Report an issue: GitHub.