gastownhall/beads · error

failed to record event: %w

Error message

failed to record event: %w

What it means

This error wraps a failure of RecordEventInTable when writing the 'closed' event to the event table after a successful close UPDATE. The issue row itself was closed, but the audit/journal event could not be recorded, so the whole transaction is rolled back and the close is reported as failed. The underlying event-write error is preserved via %w.

Source

Thrown at internal/storage/issueops/close.go:376

			return nil, fmt.Errorf("%w: issue %s", storage.ErrNotFound, id)
		}
		if qerr != nil {
			return nil, fmt.Errorf("failed to check issue existence: %w", qerr)
		}
		if types.Status(status) == types.StatusClosed {
			return &CloseResult{IsWisp: isWisp, AlreadyClosed: true}, nil
		}
		return nil, fmt.Errorf("failed to close issue: %s", id)
	}

	// A closed issue holds no lease (no-op for wisps, which are never leased).
	if err := DeleteLeaseInTx(ctx, tx, id); err != nil {
		return nil, err
	}

	if recordEvent {
		if err := RecordEventInTable(ctx, tx, eventTable, id, types.EventClosed, actor, reason); err != nil {
			return nil, fmt.Errorf("failed to record event: %w", err)
		}
	}

	recompute, err := RecomputeIsBlockedInTxWithResult(ctx, tx, affectedIssues, affectedWisps)
	if err != nil {
		return nil, fmt.Errorf("recompute is_blocked after close for %s: %w", id, err)
	}

	// Snapshot only after all derived blocked-state maintenance has completed.
	// recordEvent gates the human audit event, never the journal.
	if err := RecordEventInTx(ctx, tx, EventClose, id, actor); err != nil {
		return nil, err
	}

	return &CloseResult{IsWisp: isWisp, IssueRowsChanged: !isWisp || recompute.IssueRowsChanged}, nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped driver error (errors.Is/As) for the specific insert failure (missing table, constraint, connection).
  2. Run schema checks/migrations (bd doctor) to ensure the event table matches the binary version.
  3. Retry the close in a fresh transaction once the database is writable and healthy.
  4. Verify disk space and write permissions on the database backend.
Defensive patterns

Strategy: retry

Try / catch

err := store.CloseIssue(ctx, id, actor, reason)
if err != nil && strings.Contains(err.Error(), "failed to record event") {
    // tx rolled back; safe to retry whole close
    return retryClose(ctx, id, actor, reason, 1)
}

Prevention

When it happens

Trigger: RecordEventInTable errors while inserting into the events table inside the close transaction: missing events table, schema mismatch, constraint violation, connection loss, or context cancellation during the insert.

Common situations: Partial migrations leaving an outdated events table; disk-full or read-only database; actor or payload too long for a column; concurrent schema changes by another beads version.

Related errors


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