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

  1. Inspect the wrapped driver error for the root cause
  2. Verify the queried table (`issues` or `wisps`) exists in this database
  3. Confirm the correct UseWispsTable option matches your storage mode
  4. 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

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


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