Summary
generate:db-schema declares the locale enum with the SQL name enum__locales, but the adapter creates it in Postgres as _locales. The generated schema therefore references a type that has never existed in any database.
Two hardcoded strings that should match. A PR is attached.
Where
The adapter, which is what actually reaches the database — the SQL type name is _locales, and enum__locales is only the key in the enums map:
https://github.com/payloadcms/payload/blob/v3.85.2/packages/drizzle/src/postgres/init.ts#L22-L27
if (this.payload.config.localization) {
this.enums.enum__locales = this.pgSchema.enum(
'_locales',
this.payload.config.localization.locales.map(({ code }) => code) as [string, ...string[]],
)
}
The generator, which passes that map key where a SQL type name belongs:
https://github.com/payloadcms/payload/blob/v3.85.2/packages/drizzle/src/utilities/createSchemaGenerator.ts#L96-L98
if (this.payload.config.localization && enumImport) {
addEnum('enum__locales', this.payload.config.localization.localeCodes)
}
addEnum uses its name argument for both the exported const and the SQL name:
https://github.com/payloadcms/payload/blob/v3.85.2/packages/drizzle/src/utilities/createSchemaGenerator.ts#L86-L94
const addEnum = (name: string, options: string[]) => {
if (enumsList.some((each) => each === name)) {
return
}
enumsList.push(name)
enumDeclarations.push(
`export const ${name} = ${enumFn}('${name}', [${options.map((option) => `'${option}'`).join(', ')}])`,
)
}
That contract holds for the only other caller, which passes a real SQL type name:
https://github.com/payloadcms/payload/blob/v3.85.2/packages/drizzle/src/postgres/columnToCodeConverter.ts#L19
addEnum(column.enumName, column.options)
So the locale call site is the single place where the two diverge.
Reproducing it
This repo already contains a reproduction — the committed fixture at
https://github.com/payloadcms/payload/blob/v3.85.2/test/relationships/payload-generated-schema.ts#L26
export const enum__locales = pgEnum('enum__locales', ['en', 'de'])
while init.ts creates that type as _locales.
In any localized Postgres project, after payload generate:db-schema:
SELECT DISTINCT udt_name FROM information_schema.columns
WHERE table_schema = 'public' AND column_name = '_locale';
-- _locales
SELECT typname FROM pg_type WHERE typname = 'enum__locales';
-- 0 rows
Impact
Every _locale column in the generated schema is typed against a type that does not exist — around 20 columns in our project. With push: false the generated file is never executed, so nothing surfaces the mismatch; it is documented as the schema mirror, so it is what people read when hand-writing migrations, and DDL written from it references a nonexistent type.
Expected
pgEnum('_locales', …), matching init.ts. The exported const should keep the name enum__locales, since columnToCodeConverter.ts#L17 emits enum__locales(…) as the column builder. Only the first argument to pgEnum is wrong.
Version
Found on 3.85.2. The cited code is byte-identical on main at the time of writing (createSchemaGenerator.ts L86/L97, init.ts L23–L25 — same lines, same content), so this is current.
Related
Two other cases where generate:db-schema output disagrees with what Payload itself creates, both concerning _status, are filed separately in #17738 — they need a design decision, whereas this one does not.
Summary
generate:db-schemadeclares the locale enum with the SQL nameenum__locales, but the adapter creates it in Postgres as_locales. The generated schema therefore references a type that has never existed in any database.Two hardcoded strings that should match. A PR is attached.
Where
The adapter, which is what actually reaches the database — the SQL type name is
_locales, andenum__localesis only the key in theenumsmap:https://github.com/payloadcms/payload/blob/v3.85.2/packages/drizzle/src/postgres/init.ts#L22-L27
The generator, which passes that map key where a SQL type name belongs:
https://github.com/payloadcms/payload/blob/v3.85.2/packages/drizzle/src/utilities/createSchemaGenerator.ts#L96-L98
addEnumuses itsnameargument for both the exported const and the SQL name:https://github.com/payloadcms/payload/blob/v3.85.2/packages/drizzle/src/utilities/createSchemaGenerator.ts#L86-L94
That contract holds for the only other caller, which passes a real SQL type name:
https://github.com/payloadcms/payload/blob/v3.85.2/packages/drizzle/src/postgres/columnToCodeConverter.ts#L19
So the locale call site is the single place where the two diverge.
Reproducing it
This repo already contains a reproduction — the committed fixture at
https://github.com/payloadcms/payload/blob/v3.85.2/test/relationships/payload-generated-schema.ts#L26
while
init.tscreates that type as_locales.In any localized Postgres project, after
payload generate:db-schema:Impact
Every
_localecolumn in the generated schema is typed against a type that does not exist — around 20 columns in our project. Withpush: falsethe generated file is never executed, so nothing surfaces the mismatch; it is documented as the schema mirror, so it is what people read when hand-writing migrations, and DDL written from it references a nonexistent type.Expected
pgEnum('_locales', …), matchinginit.ts. The exported const should keep the nameenum__locales, sincecolumnToCodeConverter.ts#L17emitsenum__locales(…)as the column builder. Only the first argument topgEnumis wrong.Version
Found on 3.85.2. The cited code is byte-identical on
mainat the time of writing (createSchemaGenerator.tsL86/L97,init.tsL23–L25 — same lines, same content), so this is current.Related
Two other cases where
generate:db-schemaoutput disagrees with what Payload itself creates, both concerning_status, are filed separately in #17738 — they need a design decision, whereas this one does not.