gastownhall/beads · error

reading pre-migration dirty table diffs: %w

Error message

reading pre-migration dirty table diffs: %w

What it means

This error wraps a failure in dirtyTableSignatures, which captures pre-migration diffs (signatures) of dirty tables so MigrateUp can later prove those tables were not modified by the migration pass. If signatures cannot be read, the safety contract of #4566 (clean working set after an interrupted pass) cannot be enforced, so the migration aborts before applying anything.

Source

Thrown at internal/storage/schema/schema.go:644

	// from the changed-signature guard (the resumed rekey is about to change
	// them) and lets stageSchemaTables commit them with the rest of the pass.
	if resuming, err := anyAuxRekeyResumePending(ctx, db); err != nil {
		return 0, fmt.Errorf("reading aux rekey sentinel: %w", err)
	} else if resuming {
		for _, t := range auxRekeyTables {
			delete(dirtyBefore, t.name)
		}
	}
	touchedDirtyTables, err := mainSource.pendingMigrationDirtyTables(ctx, db, dirtyBefore)
	if err != nil {
		return 0, fmt.Errorf("checking dirty tables against pending migrations: %w", err)
	}
	if len(touchedDirtyTables) > 0 {
		return 0, &DirtyTablesError{Tables: touchedDirtyTables}
	}
	dirtyBeforeSignatures, err := dirtyTableSignatures(ctx, db, dirtyBefore)
	if err != nil {
		return 0, fmt.Errorf("reading pre-migration dirty table diffs: %w", err)
	}
	// Captured before the main migrations run: the aux re-key uses it to
	// distinguish the lineage's first rekey-aware migration (run the pass)
	// from a fresh clone of an already-converged lineage (record the marker
	// only, bd-578h9.4).
	mainVersionBefore, err := mainSource.currentVersion(ctx, db)
	if err != nil {
		return 0, fmt.Errorf("reading pre-migration schema version: %w", err)
	}

	applied, mainColumnAdded, err := mainSource.migrate(ctx, db, 0)
	if err != nil {
		return applied, err
	}

	backfilled, err := ensureBackfilledCustomStatusesCustomTypes(ctx, db)
	if err != nil {
		return applied, fmt.Errorf("backfill custom tables: %w", err)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Resolve the wrapped cause (failing diff/status query) shown after this message
  2. Stop concurrent writers to the repository before running migrations
  3. Commit or revert pre-existing working-set changes so there are no dirty tables to signature
  4. Restore the table or database from a Dolt commit if diff data is corrupt
Defensive patterns

Strategy: retry

Validate before calling

// Ensure no concurrent writers before migrating
if locked, _ := tryLock(ctx, db); !locked {
    return errors.New("another writer holds the migration lock")
}

Type guard

func isSignatureReadErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "reading pre-migration dirty table diffs")
}

Try / catch

applied, err := schema.MigrateUp(ctx, db)
if isSignatureReadErr(err) {
    // transient diff-read failure: safe to retry, nothing was applied yet
    return retryMigrateUp(ctx, db)
}

Prevention

When it happens

Trigger: Calling MigrateUp/MigrateUpWithLock when dirtyTableSignatures errors - e.g. dolt_diff/status queries on one of the pre-existing dirty tables fail, or a dirty table was dropped/renamed between the status read and this call.

Common situations: Concurrent writers mutating the working set between the two pre-flight reads; corrupt diff history on a dirty table; a table listed dirty earlier but now inaccessible.

Related errors


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