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
- Inspect the wrapped driver error (errors.Is/As) for the specific insert failure (missing table, constraint, connection).
- Run schema checks/migrations (bd doctor) to ensure the event table matches the binary version.
- Retry the close in a fresh transaction once the database is writable and healthy.
- 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
- Run schema migrations so the events table matches the binary version.
- Ensure the database is writable (disk space, permissions) before bulk closes.
- Retry the full close — the transaction rollback leaves state consistent.
- Watch for long actor/reason strings that could exceed column limits.
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
- failed to begin transaction: %w
- failed to commit is_blocked repairs: %w
- failed to close issue: %w
- failed to check issue existence: %w
- delete issues: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/8c83c72865e60546.
Report an issue: GitHub.