{"record":{"id":"31515487108834a3","repo":"multica-ai/multica","slug":"attribution-strict-constraint-pre-198-hook-w","errorCode":null,"errorMessage":"attribution strict-constraint pre-198 hook: %w","messagePattern":"attribution strict-constraint pre-198 hook: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/migrate/main.go","lineNumber":221,"sourceCode":"\t\t\t\"watermark_stamped\", res.WatermarkStamped)\n\t\treturn nil\n\t}\n\tslog.Info(\"task_usage hourly rollup hook: backfill complete\",\n\t\t\"slices\", res.SlicesProcessed,\n\t\t\"rows_touched\", res.RowsTouched,\n\t\t\"from\", res.From.Format(\"2006-01-02T15:04:05Z07:00\"),\n\t\t\"to\", res.To.Format(\"2006-01-02T15:04:05Z07:00\"))\n\treturn nil\n}\n\n// runAttributionStrictHook backfills accountable_user_id from\n// originator_user_id before migration 198 validates the strict attribution\n// constraint, so self-hosted upgrades that never ran the out-of-band\n// backfill recover automatically (GH #5544 / MUL-4897).\nfunc runAttributionStrictHook(ctx context.Context, pool *pgxpool.Pool) error {\n\tres, err := attributionbackfill.Hook(ctx, pool, attributionbackfill.HookOptions{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"attribution strict-constraint pre-198 hook: %w\", err)\n\t}\n\tslog.Info(\"attribution backfill hook: complete\",\n\t\t\"rows_backfilled\", res.RowsBackfilled,\n\t\t\"batches\", res.Batches,\n\t\t\"mismatch_normalized\", res.MismatchNormalized)\n\treturn nil\n}\n\n// migrationAdvisoryLockKey is the int64 identifier used with Postgres\n// pg_advisory_lock to serialize the migration loop across concurrent\n// runners (multi-replica backend Deployment, scale-up, or a manual\n// `migrate up` overlapping with pod startup). The exact value is\n// arbitrary — it just needs to be stable across every process that runs\n// migrations against the same database. See GitHub multica-ai/multica#3647.\nconst migrationAdvisoryLockKey int64 = 7244554146635925501\n\n// defaultSchemaMigrationsTable is the unqualified name of the bookkeeping\n// table that tracks which migrations have been applied. Tests override","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/migrate/main.go#L203-L239","documentation":"The pre-198 hook that backfills accountable_user_id from originator_user_id (attributionbackfill.Hook, GH #5544 / MUL-4897) failed, aborting the run before the strict attribution constraint migration executes. Without this hook, self-hosted databases that never ran the out-of-band backfill would fail migration 198's validation outright.","triggerScenarios":"The tasks/attribution tables or columns referenced by the backfill query are missing or have unexpected types; statement/lock timeouts while batch-updating a large tasks table; connection loss mid-batch; cancelled context.","commonSituations":"Upgrading an old self-hosted instance with many rows where accountable_user_id is NULL; a partially applied earlier migration leaving schema drift.","solutions":["Inspect the wrapped error: 42P01/42703 mean schema drift — apply/repair earlier migrations first","For timeouts on large tables, raise statement_timeout and ensure no long transactions hold locks on tasks","Re-run `migrate up` — the hook is batched and resumable, and the version is only recorded after success"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"res, err := attributionbackfill.Hook(ctx, pool, attributionbackfill.HookOptions{})\nif err != nil {\n    return fmt.Errorf(\"attribution strict-constraint pre-198 hook: %w\", err)\n}","preventionTips":["Keep schema drift out of upgraded databases — apply migrations in order","Clear long transactions on tasks before upgrading past 198","Re-run `migrate up` after fixing the wrapped cause; the hook resumes"],"tags":["go","postgres","migration","backfill","attribution"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}