gastownhall/beads · error

count wisp labels: %w

Error message

count wisp labels: %w

What it means

DeleteResolvedSetInTx aborts when it cannot count rows in the "wisp_labels" table for the wisp IDs in the resolved set. This wraps the driver-level error returned by CountRowsForIssueIDsInTx. The count contributes to the labels figure of the delete result.

Source

Thrown at internal/storage/issueops/delete.go:226

	}

	var depsCount, labelsCount, eventsCount int
	var err error
	if depsCount, err = CountRowsForIssueIDsInTx(ctx, tx, "dependencies", set.RegularIDs); err != nil {
		return nil, fmt.Errorf("count dependencies: %w", err)
	}
	wispDepsCount, err := CountRowsForIssueIDsInTx(ctx, tx, "wisp_dependencies", set.WispIDs)
	if err != nil {
		return nil, fmt.Errorf("count wisp dependencies: %w", err)
	}
	depsCount += wispDepsCount

	if labelsCount, err = CountRowsForIssueIDsInTx(ctx, tx, "labels", set.RegularIDs); err != nil {
		return nil, fmt.Errorf("count labels: %w", err)
	}
	wispLabelsCount, err := CountRowsForIssueIDsInTx(ctx, tx, "wisp_labels", set.WispIDs)
	if err != nil {
		return nil, fmt.Errorf("count wisp labels: %w", err)
	}
	labelsCount += wispLabelsCount

	if eventsCount, err = CountRowsForIssueIDsInTx(ctx, tx, "events", set.RegularIDs); err != nil {
		return nil, fmt.Errorf("count events: %w", err)
	}
	wispEventsCount, err := CountRowsForIssueIDsInTx(ctx, tx, "wisp_events", set.WispIDs)
	if err != nil {
		return nil, fmt.Errorf("count wisp events: %w", err)
	}
	eventsCount += wispEventsCount

	for i := 0; i < len(set.All); i += deleteBatchSize {
		end := i + deleteBatchSize
		if end > len(set.All) {
			end = len(set.All)
		}
		batch := set.All[i:end]

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped driver error to distinguish missing table from connection failure.
  2. Run schema migrations / ensure the backend supports wisp tables.
  3. Retry on a fresh transaction if the cause is transient.
  4. Check database server logs around the failure time.

Example fix

// before
if err != nil {
    return err
}
// after
if err != nil {
    var missing tableMissingError
    if errors.As(err, &missing) {
        return fmt.Errorf("run 'bd migrate' first: %w", err)
    }
    return err
}
Defensive patterns

Strategy: validation

Validate before calling

// confirm wisp support before calling delete on wisps
rows, err := db.QueryContext(ctx,
    `SELECT table_name FROM information_schema.tables WHERE table_name = 'wisp_labels'`)
if err != nil || !rows.Next() {
    return errors.New("wisp_labels missing: migrate schema or use a wisp-capable backend")
}

Try / catch

res, err := store.DeleteInTx(ctx, tx, ids)
if err != nil && strings.Contains(err.Error(), "wisp_labels") {
    return fmt.Errorf("backend lacks wisp support or schema is stale: %w", err)
}

Prevention

When it happens

Trigger: Calling DeleteInTx/DeleteIssuesInTx where wisp_labels is absent (pre-wisp schema or driver that doesn't create wisp tables), corrupted, or the connection fails between the labels count and this query.

Common situations: Embedded-mode or older storage backend lacking wisp_labels; Dolt schema drift after a version upgrade; transient I/O error on the database file/server.

Related errors


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