{"record":{"id":"92f45a6b5d604992","repo":"gastownhall/beads","slug":"checking-pre-existing-dirty-table-diffs-w","errorCode":null,"errorMessage":"checking pre-existing dirty table diffs: %w","messagePattern":"checking pre-existing dirty table diffs: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/schema/schema.go","lineNumber":724,"sourceCode":"\t\t// there is no dirty-commit recovery story to support here the way\n\t\t// there is for the main-source guard (#4566 scope).\n\t\treturn applied, fmt.Errorf(\"pending ignored schema migrations alter pre-existing dirty tables: %s\", strings.Join(touchedIgnoredDirtyTables, \", \"))\n\t}\n\n\tappliedIgnored, ignoredColumnAdded, err := ignoredSource.migrate(ctx, db, 0)\n\tif err != nil {\n\t\treturn applied, fmt.Errorf(\"ignored migrations: %w\", err)\n\t}\n\tif err := unstageIgnoredTables(ctx, db); err != nil {\n\t\treturn applied, fmt.Errorf(\"unstaging ignored migration tables: %w\", err)\n\t}\n\n\tif applied == 0 && !backfilled && appliedIgnored == 0 && !mainColumnAdded && !ignoredColumnAdded {\n\t\treturn applied, nil\n\t}\n\tchangedDirtyTables, err := changedDirtyTableSignatures(ctx, db, dirtyBeforeSignatures)\n\tif err != nil {\n\t\treturn applied, fmt.Errorf(\"checking pre-existing dirty table diffs: %w\", err)\n\t}\n\tif len(changedDirtyTables) > 0 {\n\t\treturn applied, fmt.Errorf(\"pre-existing dirty tables changed during schema migration: %s\", strings.Join(changedDirtyTables, \", \"))\n\t}\n\n\tstaged, err := stageSchemaTables(ctx, db, dirtyBefore)\n\tif err != nil {\n\t\treturn applied, fmt.Errorf(\"staging migrations: %w\", err)\n\t}\n\tif !staged {\n\t\treturn applied, nil\n\t}\n\tif err := DrainCall(ctx, db, \"CALL DOLT_COMMIT('-m', 'schema: apply migrations')\"); err != nil {\n\t\tif !strings.Contains(strings.ToLower(err.Error()), \"nothing to commit\") {\n\t\t\treturn applied, fmt.Errorf(\"committing migrations: %w\", err)\n\t\t}\n\t}\n","sourceCodeStart":706,"sourceCodeEnd":742,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/schema/schema.go#L706-L742","documentation":"After all migrations and backfills apply, MigrateUp compares signatures of pre-existing dirty tables against snapshots taken before the pass (changedDirtyTableSignatures) to prove the migration never mutated user data in dirty tables. This error wraps a failure of that comparison query itself — it is a diagnostic failure, not evidence of data change. MigrateUp aborts before staging/committing so a broken verification never lets an unverifiable pass be checkpointed.","triggerScenarios":"Calling MigrateUp/MigrateUpWithLock when changedDirtyTableSignatures(ctx, db, dirtyBeforeSignatures) errors — e.g. the dirty-table signature query fails because a dirty table was dropped/renamed mid-pass, a SQL/driver error occurs while reading table signatures, or the connection fails during the check.","commonSituations":"Another process mutating schema (dropping tables) while MigrateUp runs, corrupted table metadata that the signature query cannot read, connection timeouts on large databases between the pre- and post-pass reads, or driver-level SQL errors in the signature introspection queries.","solutions":["Check the wrapped cause (%w) for the failing introspection query and fix the underlying SQL/driver error","Ensure no concurrent process is altering or dropping tables during migration — run MigrateUp under the advisory lock (MigrateUpWithLock) and stop competing writers, then re-run","Verify the database connection is stable (no mid-pass disconnects) and re-run on a healthy connection","If a dirty table's metadata is unreadable/corrupt, repair or restore that table before migrating again","Re-run MigrateUp after fixing; migrations already applied, only verification and staging were skipped"],"exampleFix":"// before: migrating without a lock while another writer drops tables\n_, err := schema.MigrateUp(ctx, db)\n// after: take the advisory lock so no concurrent DDL races the diff check\n_, err := schema.MigrateUpWithLock(ctx, db)","handlingStrategy":"try-catch","validationCode":"// Pre-flight: stable connection and no concurrent DDL expected\nif err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"unstable connection before migrate: %w\", err)\n}\n// Check for dirty tables whose state the diff check will read\n// (MigrateUp itself guards against dirty tables; verify lock availability)\n// Prefer the locked entry point:\n// applied, err := schema.MigrateUpWithLock(ctx, db)","typeGuard":null,"tryCatchPattern":"applied, err := schema.MigrateUpWithLock(ctx, db)\nif err != nil {\n    if strings.Contains(err.Error(), \"checking pre-existing dirty table diffs:\") {\n        cause := errors.Unwrap(err)\n        return fmt.Errorf(\"migration diff verification failed (%v); migrations applied but not staged/committed — fix and re-run\", cause)\n    }\n    return err\n}","preventionTips":["Use MigrateUpWithLock to exclude concurrent DDL from racing the diff check","Avoid dropping/renaming tables manually while an upgrade is in progress","Keep connections alive for the duration of long migrations (raise timeouts)","Repair corrupt tables before migrating so signature queries can read them"],"tags":["database","migration","verification","dolt"],"backgroundTag":"migration-verification-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}