gastownhall/beads · error

db: LabelSQLRepository.Insert %s/%s: issue does not exist

Error message

db: LabelSQLRepository.Insert %s/%s: issue does not exist

What it means

Returned when INSERT IGNORE affected 0 rows and the verification query confirms the parent issue does not exist in the issues (or wisps) table. The library treats this as a caller error: you are adding a label to a nonexistent issue, so nothing is inserted and no event is journaled.

Source

Thrown at internal/storage/domain/db/label.go:73

	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)
}

func (r *labelSQLRepositoryImpl) Delete(ctx context.Context, issueID, label, actor string, opts domain.LabelOpts) error {
	if issueID == "" {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Create the issue first, then insert the label
  2. Verify the issue ID exists (e.g. `bd show <id>`) before labeling
  3. Check UseWispsTable matches the table the issue actually resides in
  4. Use the full canonical issue ID, not a prefix

Example fix

// before
repo.Insert(ctx, "bd-abc", "bug", opts) // ID may not exist
// after
if _, err := issueRepo.Get(ctx, "bd-abc-1234"); err != nil { return err }
return repo.Insert(ctx, "bd-abc-1234", "bug", opts)
Defensive patterns

Strategy: validation

Validate before calling

func issueExists(ctx context.Context, db *sql.DB, id string, wisps bool) (bool, error) {
    t := "issues"; if wisps { t = "wisps" }
    var n int
    if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM "+t+" WHERE id = ?", id).Scan(&n); err != nil { return false, err }
    return n > 0, nil
}

Try / catch

if err := repo.Insert(ctx, issueID, label, opts); err != nil {
    if strings.Contains(err.Error(), "issue does not exist") {
        return fmt.Errorf("cannot label %s: create the issue first", issueID)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Insert with an issueID that was never created, was deleted, or an ID format mismatch (e.g. using a short prefix instead of the full ID); Insert into wisps mode when the issue lives in `issues` instead.

Common situations: Stale client cache holding a deleted issue ID; passing a wisp ID while UseWispsTable is false; race where the issue was removed between read and label insert; typos in hand-built IDs.

Related errors


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