@@ -499,10 +499,28 @@ async function migratePostgresTable(
499499 const escapedBrainId = brainId . replace ( / ' / g, "''" ) ;
500500
501501 if ( table . brainIdSourceColumn ) {
502- // Add nullable, then UPDATE from source column, then SET NOT NULL.
503- await adapter . exec ( `ALTER TABLE ${ table . name } ADD COLUMN brain_id TEXT` ) ;
504- await adapter . exec ( `UPDATE ${ table . name } SET brain_id = ${ table . brainIdSourceColumn } ` ) ;
505- await adapter . exec ( `ALTER TABLE ${ table . name } ALTER COLUMN brain_id SET NOT NULL` ) ;
502+ // Defensive: an old archived_traces table might exist without the
503+ // expected source column (e.g., schema drift from manual SQL or pre-
504+ // archive-feature deployments). Mirror the SQLite path's column-existence
505+ // check (see migrateSqliteTable) so a missing source column falls back
506+ // to the supplied brainId default rather than crashing the migration.
507+ const hasSourceColumn = await postgresHasColumn (
508+ adapter ,
509+ table . name ,
510+ table . brainIdSourceColumn ,
511+ ) ;
512+ if ( hasSourceColumn ) {
513+ await adapter . exec ( `ALTER TABLE ${ table . name } ADD COLUMN brain_id TEXT` ) ;
514+ await adapter . exec ( `UPDATE ${ table . name } SET brain_id = ${ table . brainIdSourceColumn } ` ) ;
515+ await adapter . exec ( `ALTER TABLE ${ table . name } ALTER COLUMN brain_id SET NOT NULL` ) ;
516+ } else {
517+ // Source column missing: fall back to the supplied brainId default,
518+ // same as the no-source-column path.
519+ await adapter . exec (
520+ `ALTER TABLE ${ table . name } ADD COLUMN brain_id TEXT NOT NULL DEFAULT '${ escapedBrainId } '` ,
521+ ) ;
522+ await adapter . exec ( `ALTER TABLE ${ table . name } ALTER COLUMN brain_id DROP DEFAULT` ) ;
523+ }
506524 } else {
507525 await adapter . exec (
508526 `ALTER TABLE ${ table . name } ADD COLUMN brain_id TEXT NOT NULL DEFAULT '${ escapedBrainId } '` ,
0 commit comments