{"record":{"id":"bfa853d5050e3f05","repo":"gastownhall/beads","slug":"uow-migrate-w","errorCode":null,"errorMessage":"uow: migrate: %w","messagePattern":"uow: migrate: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/storage/uow/dolt_sql_provider.go","lineNumber":87,"sourceCode":"\nfunc (e *bootstrapPreparationError) Error() string {\n\treturn e.err.Error()\n}\n\nfunc (e *bootstrapPreparationError) Unwrap() error {\n\treturn e.err\n}\n\nfunc classifyInitSchemaError(err error) error {\n\tvar preparationErr *bootstrapPreparationError\n\tif errors.As(err, &preparationErr) {\n\t\tif preparationErr.retryable {\n\t\t\treturn fmt.Errorf(\"uow: bootstrap preparation: %w\", err)\n\t\t}\n\t\treturn backoff.Permanent(err)\n\t}\n\tif isSerializationError(err) || schema.IsMigrationLockError(err) {\n\t\treturn fmt.Errorf(\"uow: migrate: %w\", err)\n\t}\n\treturn backoff.Permanent(fmt.Errorf(\"uow: migrate: %w\", err))\n}\n\n// ProviderOption tunes how a SQL-server unit-of-work provider opens. Options\n// are variadic so the existing constructor call sites — every one of which\n// wants the ordinary mutating open — stay unchanged.\ntype ProviderOption func(*providerOptions)\n\ntype providerOptions struct {\n\t// preview opens for a command that promised not to mutate anything\n\t// (--dry-run, --inspect). Such a command must reach its own RunE before\n\t// anything writes, so the open may neither CREATE DATABASE nor run\n\t// MigrateUpWithLock: both happen during root pre-run, before the flag the\n\t// user passed has had any effect. An absent or behind database is\n\t// reported by the preview's own query rather than repaired implicitly —\n\t// the same contract embeddeddolt.OpenForPreviewCommand gives the embedded\n\t// path.","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/uow/dolt_sql_provider.go#L69-L105","documentation":"classifyInitSchemaError wraps errors that are serialization failures or migration-lock errors as 'uow: migrate: %w', returning them as retryable (bare) errors so the backoff loop retries the schema migration. It signals that another session's migration or a transaction serialization conflict blocked this attempt.","triggerScenarios":"initSchemaAttempt calls schema.MigrateUpWithLock, which fails with a serialization error (isSerializationError) or a migration lock error (schema.IsMigrationLockError); classifyInitSchemaError wraps it so backoff retries.","commonSituations":"Two bd processes starting simultaneously against a fresh shared Dolt server; a peer process mid-migration holding the schema migration lock; Dolt transaction serialization conflicts on a busy server.","solutions":["Let the 60s backoff budget in initSchema retry — the peer's migration should finish and the retry converge.","Reduce concurrent cold starts: stagger or serialize the first bd invocations against a new shared server.","Confirm the peer holding the lock is healthy; a crashed peer can hold the lock until timeout.","Inspect the wrapped error if retries exhaust — it names the conflicting session or lock."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// before opening: confirm no peer currently holds the migration lock\nrows, err := adminConn.QueryContext(ctx,\n    \"SELECT COUNT(*) FROM information_schema.processlist WHERE info LIKE '%MigrateUpWithLock%'\")","typeGuard":"if schema.IsMigrationLockError(err) || uow.IsSerializationError(err) { /* retryable: re-attempt open */ }","tryCatchPattern":"err := provider.Open(ctx, cfg)\nif err != nil {\n    if uow.IsSerializationError(err) || schema.IsMigrationLockError(err) {\n        // transient contention — retry with exponential backoff\n        return backoff.Retry(openFn, bo)\n    }\n    return err\n}","preventionTips":["Serialize first-run initialization across the team (one process migrates, others wait).","Keep a 60s+ budget for cold starts against shared servers.","Upgrade all bd clients together so no peer stalls mid-migration.","Monitor for lock-holder crashes that leave the lock until timeout."],"tags":["database","migration","concurrency","retry"],"backgroundTag":"migration-lock-contention","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}