{"record":{"id":"a006a595ef72b146","repo":"gastownhall/beads","slug":"creating-wisps-for-migration-0047-w","errorCode":null,"errorMessage":"creating wisps for migration 0047: %w","messagePattern":"creating wisps for migration 0047: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/schema/migration_repairs.go","lineNumber":206,"sourceCode":"// after 0020) and, on a database whose local wisp_dependencies predates\n// 0022, expects idx_wisp_dep_type to already exist. Creating the 0020/0021-era\n// shape here is exactly the #4695 bug shape one migration later: a real\n// production repro hit \"table not found: wisps\" at 0047 and \"unknown column\n// no_history\" at 0053 back to back (see the failed-workaround log in #4695).\n// wispsTableDDLForMigration0047 / wispDependenciesTableDDLForMigration0047\n// below are therefore the full shape as of immediately before 0053 runs --\n// every column/index any main migration <=52 adds to these tables -- verified\n// by building a bounded fresh chain (migrations 1..52 only) and comparing\n// against SHOW CREATE TABLE, not by manual inspection. Nothing from 54/55\n// (lease columns added then removed again) or 56 belongs here.\nfunc ensureWispTablesForMixedBlockedRecompute(ctx context.Context, db DBConn) error {\n\thasWisps, err := schemaTableExists(ctx, db, \"wisps\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"checking wisps table: %w\", err)\n\t}\n\tif !hasWisps {\n\t\tif _, err := db.ExecContext(ctx, wispsTableDDLForMigration0047); err != nil {\n\t\t\treturn fmt.Errorf(\"creating wisps for migration 0047: %w\", err)\n\t\t}\n\t}\n\n\thasWispDeps, err := schemaTableExists(ctx, db, \"wisp_dependencies\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"checking wisp_dependencies table: %w\", err)\n\t}\n\tif !hasWispDeps {\n\t\tif _, err := db.ExecContext(ctx, wispDependenciesTableDDLForMigration0047); err != nil {\n\t\t\treturn fmt.Errorf(\"creating wisp_dependencies for migration 0047: %w\", err)\n\t\t}\n\t\treturn nil\n\t}\n\n\treturn ensureWispDependenciesSplitTargets(ctx, db)\n}\n\n// ensureWispIsBlockedForRecompute repairs a drift shape in ignored/0006's own","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/schema/migration_repairs.go#L188-L224","documentation":"When wisps is entirely missing, the pre-0047 repair creates it from wispsTableDDLForMigration0047 (the forward-canonical shape through v52, so later migrations like 0053 find no_history/started_at). This error wraps failure of that CREATE TABLE — SQL rejected the DDL, typically from a connection drop, a conflicting stale object, or a server DDL error.","triggerScenarios":"Clone hitting migration 0047 without wisps (dolt_ignore'd tables never sync to clones; #4695 shape) and CREATE TABLE IF NOT EXISTS wisps (...) fails — connection drop mid-DDL, name collision with leftover objects, or server DDL rejection.","commonSituations":"Clone right after a schema bump before producers re-pushed; pre-1.0 database with stale cursor numbering treating 0020/0021 as applied; interrupted prior init attempt.","solutions":["Retry bd init — the DDL uses CREATE TABLE IF NOT EXISTS and is safe to re-run","Check for a leftover conflicting object named wisps and remove it if stale","Verify connectivity to the Dolt sql-server and retry","Inspect the wrapped error; subsequent \"unknown column no_history\" at 0053 means the create still did not take"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// ensure no conflicting object exists before the DDL\nvar n int\ndb.QueryRowContext(ctx, `SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES\n  WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wisps'`).Scan(&n)\n// n == 0 means the CREATE TABLE IF NOT EXISTS path is safe; n > 0 means it will be skipped","typeGuard":null,"tryCatchPattern":"if _, err := db.ExecContext(ctx, wispsTableDDLForMigration0047); err != nil {\n    if isTransient(err) {\n        return ensureWispTablesForMixedBlockedRecompute(ctx, db) // IF NOT EXISTS makes re-run safe\n    }\n    return err\n}","preventionTips":["Retry init on transient failures — DDL is CREATE TABLE IF NOT EXISTS","Remove stale leftover objects named wisps from interrupted prior inits","Ensure the created shape stays forward-canonical (through v52) so 0053 finds no_history/started_at","Watch for \"unknown column no_history\" at 0053 as a signal the create never took"],"tags":["dolt","migration","ddl","clone-skew"],"backgroundTag":"table-not-found","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}