gastownhall/beads · error

count wisp events: %w

Error message

count wisp events: %w

What it means

DeleteResolvedSetInTx aborts when it cannot count rows in the "wisp_events" table for the wisp IDs being deleted. This wraps the driver error from CountRowsForIssueIDsInTx and completes the events count for the dry-run delete result.

Source

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

		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]
		batchInClause, batchArgs := buildSQLInClause(batch)

		for _, depTable := range []string{"dependencies", "wisp_dependencies"} {
			rows, err := tx.QueryContext(ctx,
				fmt.Sprintf(`SELECT issue_id FROM %s WHERE %s`, depTable, depTargetIn("", batchInClause)),
				batchArgs...)
			if err != nil {
				if optionalBlockedTable(depTable) && isTableNotExistError(err) {
					continue

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped error to identify missing-table vs connection causes.
  2. Apply schema migrations so wisp_events exists.
  3. Retry with a fresh transaction if the cause was transient.
  4. Confirm backend/driver support for wisp tables (see the storage boundary docs).

Example fix

// before
res, err := store.DeleteIssuesInTx(ctx, tx, ids)
// after
if err := migrator.EnsureSchema(ctx); err != nil {
    return fmt.Errorf("schema out of date: %w", err)
}
res, err := store.DeleteIssuesInTx(ctx, tx, ids)
Defensive patterns

Strategy: validation

Validate before calling

var name string
err := db.QueryRowContext(ctx,
    `SELECT table_name FROM information_schema.tables WHERE table_name = 'wisp_events'`).Scan(&name)
if err != nil {
    return errors.New("wisp_events missing: run schema migration before deleting wisps")
}

Try / catch

res, err := store.DeleteInTx(ctx, tx, ids)
if err != nil && strings.Contains(err.Error(), "wisp_events") {
    return fmt.Errorf("schema missing wisp_events; run migration: %w", err)
}

Prevention

When it happens

Trigger: Calling DeleteIssuesInTx/DeleteInTx when wisp_events does not exist (older schema, unsupported embedded driver) or the connection/transaction fails at this point in the count sequence.

Common situations: Version mismatch between beads binary and on-disk schema (wisp_events not yet migrated); Dolt server restart mid-delete; disk I/O errors on embedded databases.

Related errors


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