gastownhall/beads · error
db: LabelSQLRepository.Insert %s/%s: verify issue: %w
Error message
db: LabelSQLRepository.Insert %s/%s: verify issue: %w
What it means
Thrown when the repository's follow-up verification SELECT COUNT(*) on the parent issue (in `issues` or `wisps`) fails after INSERT IGNORE reported 0 rows affected. This means 0 rows were inserted AND the existence check itself errored, so the repository cannot distinguish a missing issue from a DB problem.
Source
Thrown at internal/storage/domain/db/label.go:70
fmt.Sprintf("INSERT IGNORE INTO %s (issue_id, label) VALUES (?, ?)", table),
issueID, label,
)
if err != nil {
return fmt.Errorf("db: LabelSQLRepository.Insert %s/%s: %w", issueID, label, err)
}
rows, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("db: LabelSQLRepository.Insert %s/%s: rows affected: %w", issueID, label, err)
}
if rows == 0 {
issueTable := "issues"
if opts.UseWispsTable {
issueTable = "wisps"
}
var count int
//nolint:gosec // G201: issueTable is one of two hardcoded constants.
if err := r.runner.QueryRowContext(ctx, fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE id = ?", issueTable), issueID).Scan(&count); err != nil {
return fmt.Errorf("db: LabelSQLRepository.Insert %s/%s: verify issue: %w", issueID, label, err)
}
if count == 0 {
return fmt.Errorf("db: LabelSQLRepository.Insert %s/%s: issue does not exist", issueID, label)
}
return nil
}
if err := r.events.Record(ctx, domain.Event{
IssueID: issueID,
Type: types.EventLabelAdded,
Actor: actor,
NewValue: label,
}, domain.RecordEventOpts{UseWispsTable: opts.UseWispsTable}); err != nil {
return err
}
// A label is part of the bead snapshot; the idempotent no-op path above
// returns without writing and journals nothing.
return issueops.RecordEventInTx(ctx, r.runner, issueops.EventUpdate, issueID, actor)
}View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped driver error for the root cause
- Verify the queried table (`issues` or `wisps`) exists in this database
- Confirm the correct UseWispsTable option matches your storage mode
- Re-run the operation after restoring connectivity
Defensive patterns
Strategy: try-catch
Validate before calling
var n int
err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM wisps WHERE id = ?", issueID).Scan(&n)
if err != nil { return err }
if n == 0 { return fmt.Errorf("issue %s does not exist", issueID) } Type guard
func isMissingTableErr(err error) bool { var e *mysql.MySQLError; return errors.As(err, &e) && e.Number == 1146 } Try / catch
if err := repo.Insert(ctx, issueID, label, opts); err != nil {
var sqle *mysql.MySQLError
if errors.As(err, &sqle) && sqle.Number == 1146 { log.Error("labels/verify table missing; run migrations") }
return err
} Prevention
- Pre-check the issue exists before labeling
- Run schema migrations before using the DB
- Match UseWispsTable to your storage mode
- Grant SELECT privileges to the app user
When it happens
Trigger: Insert called with an issueID that yields 0 affected rows (duplicate label or truly missing issue) and the verification query hits a DB error (connection loss, wrong table, permissions).
Common situations: UseWispsTable set but the `wisps` table does not exist in the database; connection dropped between insert and verify; insufficient SELECT privileges.
Related errors
- failed to begin transaction: %w
- failed to recompute is_blocked: %w
- failed to commit is_blocked repairs: %w
- %s: %w
- failed to query orphaned dependencies: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b06948c67cf8f7bd.
Report an issue: GitHub.