gastownhall/beads · error

backfilling dependencies.id for migration 0053: %w

Error message

backfilling dependencies.id for migration 0053: %w

What it means

This wraps the SQL error raised while backfilling the new `dependencies.id` column (migration 0053 repair). The repair assigns each dependency row a deterministic CHAR(36) id derived from its (issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external) natural identity via an UPDATE; this error means that UPDATE failed for one of those rows.

Source

Thrown at internal/storage/schema/migration_repairs.go:499

		target := firstNonNullString(e.dependsOnIssueID, e.dependsOnWispID, e.dependsOnExternal)
		if target == "" {
			// ck_dep_one_target (0041) should make a targetless row
			// unreachable; if one exists anyway, leave its id NULL here --
			// ensureDependenciesIDPrimaryKey below checks for exactly this
			// and fails loudly with an actionable count instead of letting a
			// blind MODIFY ... NOT NULL hard-fail on it, or silently keying
			// the table while pretending the row doesn't exist.
			continue
		}
		id := depid.New(e.issueID, target)
		if _, err := db.ExecContext(ctx, `
			UPDATE dependencies SET id = ?
			WHERE issue_id = ?
			  AND depends_on_issue_id <=> ?
			  AND depends_on_wisp_id <=> ?
			  AND depends_on_external <=> ?
		`, id, e.issueID, e.dependsOnIssueID, e.dependsOnWispID, e.dependsOnExternal); err != nil {
			return fmt.Errorf("backfilling dependencies.id for migration 0053: %w", err)
		}
	}
	return nil
}

// ensureDependenciesIDPrimaryKey finishes restoring dependencies.id to 0043's
// canonical shape: NOT NULL and the table's PRIMARY KEY. It re-verifies both
// independently of whether this pass just backfilled anything, so a re-entry
// after a crash between the backfill and the key (or between MODIFY NOT NULL
// and ADD PRIMARY KEY) finishes the remaining step(s) instead of re-running
// ones already done -- MODIFY COLUMN restating an identical definition and
// re-adding an already-present PRIMARY KEY are otherwise either redundant or
// outright rejected as a duplicate key.
func ensureDependenciesIDPrimaryKey(ctx context.Context, db DBConn) error {
	var remainingNull int
	if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM dependencies WHERE id IS NULL").Scan(&remainingNull); err != nil {
		return fmt.Errorf("counting unbackfilled dependencies.id rows for migration 0053: %w", err)
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Rerun the command once the database is reachable and no other bd process is running; the backfill is resumable and skips rows already assigned an id
  2. Check database connectivity and Dolt server logs for the underlying %w cause (lock wait timeout, connection refused, etc.)
  3. If locks are the cause, kill lingering bd processes (`ps aux | grep bd`) or stale Dolt transactions, then retry
  4. As a last resort, back up the database and restore, then let migration run on a clean copy

Example fix

// before: concurrent lock during backfill
bd ready  // fails: backfilling dependencies.id for migration 0053: lock wait timeout
// after: ensure no competing process, then retry
pkill -f 'bd ' ; bd ready  // migration resumes and completes
Defensive patterns

Strategy: retry

Validate before calling

// preflight: ensure single writer and reachable db
bd dolt sql -q 'SELECT COUNT(*) FROM dependencies WHERE id IS NULL' || echo 'db unreachable or locked'

Try / catch

// Go caller of the schema-ensure step
if err := schema.Ensure(ctx, db); err != nil {
    if strings.Contains(err.Error(), "backfilling dependencies.id") && isTransient(err) {
        time.Sleep(backoff); continue // retry: resumable backfill
    }
    return err
}

Prevention

When it happens

Trigger: Running the migration-0053 repair path (ensureDependenciesIDColumn -> backfillDependenciesID) against a Dolt/MySQL database where the per-row `UPDATE dependencies SET id = ? ...` statement fails — e.g. connection dropped mid-backfill, lock timeout on a concurrently written dependencies table, or the column was added but a statement-level constraint rejects the computed value.

Common situations: Upgrading an older beads database whose dependencies table predates 0053; starting `bd` (which runs ensureSchema) while another bd process holds row locks on dependencies; network/daemon interruption to the embedded Dolt server during startup repair.

Related errors


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