gastownhall/beads · error

record wake event for %s: %w

Error message

record wake event for %s: %w

What it means

Thrown when RecordFullEventInTable fails while journaling the deferred→open status-change event for a freshly woken issue. The row was already updated to 'open' in the same transaction, so this error leaves a woken bead without its status-change history entry; the whole transaction aborts via the returned error.

Source

Thrown at internal/storage/issueops/wake_defers.go:133

		res, err := tx.ExecContext(ctx, fmt.Sprintf(`
			UPDATE %s
			SET status = 'open', defer_until = NULL, updated_at = ?, row_lock = ?
			WHERE id = ? AND status = 'deferred' AND defer_until IS NOT NULL
			  AND defer_until <= UTC_TIMESTAMP()
		`, table), now, freshRowLock(), id)
		if err != nil {
			return woken, fmt.Errorf("wake expired defer %s: %w", id, err)
		}
		n, err := res.RowsAffected()
		if err != nil {
			return woken, fmt.Errorf("wake expired defer %s rows affected: %w", id, err)
		}
		if n == 0 {
			continue // rescued concurrently — leave it be
		}
		if err := RecordFullEventInTable(ctx, tx, eventsTable, id, types.EventStatusChanged,
			DeferWakeActor, string(types.StatusDeferred), string(types.StatusOpen)); err != nil {
			return woken, fmt.Errorf("record wake event for %s: %w", id, err)
		}
		// A wake is a status change, so it journals as an update. Emitted past
		// the rows-affected re-check, so a concurrently-rescued bead records
		// nothing.
		if err := RecordEventInTx(ctx, tx, EventUpdate, id, DeferWakeActor); err != nil {
			return woken, err
		}
		woken = append(woken, id)
	}
	return woken, nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause and verify the events table exists with the expected schema.
  2. Confirm the correct events table name is passed to WakeExpiredDefersInTx (not the issues table).
  3. Run storage migrations so the events table matches the current beads version.
  4. Retry after fixing — the transaction rolls back atomically so no partial state persists.

Example fix

// before: wrong table argument
WakeExpiredDefersInTx(ctx, tx, "issues", "issues", now)
// after
WakeExpiredDefersInTx(ctx, tx, "issues", "issue_events", now)
Defensive patterns

Strategy: validation

Validate before calling

var exists string
err := db.QueryRow("SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_NAME='issue_events'").Scan(&exists)
if err != nil { return errors.New("issue_events table missing: run beads migration") }

Try / catch

if err != nil {
    return fmt.Errorf("wake transaction rolled back; issue %s remains deferred: %w", id, err)
    // atomicity guarantees no half-woken state; fix events table and retry
}

Prevention

When it happens

Trigger: Calling WakeExpiredDefersInTx when inserting into the events table fails: missing/wrong events table name, schema mismatch in the events columns, connection failure, or constraint violation inside the transaction.

Common situations: Events table not created by migration; mismatched events-table parameter (issues table passed where events table expected); disk-full or duplicated-event constraint on the backend.

Related errors


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