gastownhall/beads · error

re-key id %s -> %s: %w

Error message

re-key id %s -> %s: %w

What it means

The per-row failure of the re-key loop: an UPDATE <table> SET id = ? WHERE id = ? failed while rewriting one dependency edge from its old (random UUID) id to the deterministic depid value. The message names both ids so the exact offending row is identifiable. Any row already at its deterministic id is skipped, so this only fires on genuinely divergent rows.

Source

Thrown at internal/storage/schema/dep_id_backfill.go:90

		if !target.Valid {
			// Malformed row with no target (ck_dep_one_target should prevent this);
			// leave it untouched for `bd doctor` to surface rather than guessing.
			continue
		}
		if want := depid.New(issueID, target.String); want != id {
			todo = append(todo, rekey{oldID: id, newID: want})
		}
	}
	_ = rows.Close()
	if err := rows.Err(); err != nil {
		return false, err
	}

	for _, r := range todo {
		//nolint:gosec // G201: table is a hardcoded constant, never user input.
		if _, err := db.ExecContext(ctx, fmt.Sprintf(`UPDATE %s SET id = ? WHERE id = ?`, table),
			r.newID, r.oldID); err != nil {
			return true, fmt.Errorf("re-key id %s -> %s: %w", r.oldID, r.newID, err)
		}
	}
	return len(todo) > 0, nil
}

// columnExists reports whether table.column is present in the current schema.
func columnExists(ctx context.Context, db DBConn, table, column string) (bool, error) {
	var count int
	if err := db.QueryRowContext(ctx,
		`SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
		 WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?`,
		table, column).Scan(&count); err != nil {
		return false, err
	}
	return count > 0, nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Deduplicate edges first: find rows sharing (issue_id, target) and delete extras so only one row can claim each deterministic id
  2. Check for foreign keys or unique keys referencing the old id and resolve/update them before re-keying
  3. Retry the migration — already-updated rows are skipped, so it resumes at the failed row
  4. Inspect the row by id (`SELECT * FROM dependencies WHERE id = '<oldID>'`) to confirm its shape before manual fixes

Example fix

-- before: duplicate edges with different random ids collide
DELETE d1 FROM dependencies d1 JOIN dependencies d2
  ON d1.issue_id = d2.issue_id
 AND COALESCE(d1.depends_on_issue_id, d1.depends_on_wisp_id, d1.depends_on_external) =
     COALESCE(d2.depends_on_issue_id, d2.depends_on_wisp_id, d2.depends_on_external)
 AND d1.id > d2.id;
-- after: re-run migration; remaining row re-keys cleanly
Defensive patterns

Strategy: validation

Validate before calling

-- before rekey, ensure no row already occupies the target deterministic id
SELECT COUNT(*) FROM dependencies WHERE id = '<expected deterministic id>';

Try / catch

if _, err := db.Exec("UPDATE dependencies SET id = ? WHERE id = ?", newID, oldID); err != nil {
    if dberrors.IsUniqueViolation(err) {
        // delete/merge the duplicate edge holding newID, then retry
    }
    return err
}

Prevention

When it happens

Trigger: The UPDATE statement for a specific (oldID → newID) pair errors: most commonly a unique-key collision (another row already holds newID — duplicate edges), a foreign-key reference still pointing at oldID, connection loss, or lock contention with a concurrent writer.

Common situations: Two identical dependency edges exist with different random UUIDs — the first UPDATE wins, the second collides on the deterministic id; a foreign key on dependencies.id blocks the rename; Dolt server under concurrent migration from a peer.

Related errors


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