fix(drizzle): validate companion table name length against 63-char limit - #17563
Merged
nathanlentz merged 3 commits intoJul 30, 2026
Merged
Conversation
nathanlentz
reviewed
Jul 30, 2026
nathanlentz
previously approved these changes
Jul 30, 2026
PatrikKozak
approved these changes
Jul 30, 2026
PatrikKozak
added a commit
that referenced
this pull request
Jul 30, 2026
…mit (#17567) Mirror of #17563 which targets `3.x` ## The bug Payload validates base table names against Postgres's 63-char limit, but the companion tables (`_locales`, `_rels`, `_texts`, `_numbers`) are built by concatenation afterward and never checked. A base name in the 56-63 char window passes, while its companion silently overflows and Postgres truncates it - leaving the DB schema out of sync with what Payload thinks it created (in dev, `push` then prompts `Is <table> created or renamed?` on every boot). ```ts { slug: 'a_fairly_long_collection_slug_that_is_still_under_63_chars', // base ≤ 63 → OK fields: [{ name: 'title', type: 'text', localized: true }] } // ..._locales (+8) → silently truncated ``` ## The fix Extract the 63-char check out of `createTableName` into a reusable `validateIdentifierLength`, and apply it at the 4 companion-table definition sites in `schema/build.ts`. Over-long companions now fail fast with the existing error + `dbName` tip. ## Tests - Unit - `validateIdentifierLength.spec.ts`: throws over 63, passes at/under. - Regression - `buildRawSchema.spec.ts`: an overflowing `_locales` now throws in-memory. - Cherry-picked the two new `buildRawSchema.spec.ts` fixtures now explicitly set `versions: false` since main defaults collections to `versions: true` as of #16871 (landed after this PR's original base), which otherwise requires `timestamps` and fails these fixtures for unrelated reasons. --------- Co-authored-by: Kacper Zawojski <zawojskikacperkontakt@gmail.com> Co-authored-by: Patrik Kozak <35232443+PatrikKozak@users.noreply.github.com>
nathanlentz
enabled auto-merge (squash)
July 30, 2026 14:58
Contributor
|
🚀 This is included in version v3.87.0 |
PatrikKozak
added a commit
that referenced
this pull request
Aug 14, 2026
) Surfaces Postgres identifier truncation instead of letting it silently desync the schema. Postgres truncates any identifier over 63 characters. Payload builds column and inline index/foreign-key names by concatenating nested field paths, so deeply nested fields can exceed the limit. Postgres then stores a shorter name than Payload's schema and migration snapshot expect, and dev `push` hangs on a repeated `is <column> created or renamed?` prompt on every boot. #17563 addressed this for table names by throwing, but that only reaches base and companion tables. Columns and inline index/foreign-key names were still truncated silently, and throwing outright blocks existing installs that already carry a truncated name from upgrading. Adds `checkTruncatedIdentifiers`, run during postgres `init` after `beforeSchemaInit`: - Warns (dev only) when a single identifier exceeds 63 characters, so existing installs keep booting. - Throws when two identifiers truncate to the same name, since Postgres cannot create that schema anyway — and a colliding schema could never have booted, so this never breaks a running app. Base table and enum names still throw during construction via `validateIdentifierLength`, unchanged. Related: softens the companion-table checks from #17563 (`_locales`, `_rels`, `_texts`, `_numbers`) from a hard throw to the same warn-or-collision handling.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
Payload validates base table names against Postgres's 63-char limit, but the companion tables (
_locales,_rels,_texts,_numbers) are built by concatenation afterward and never checked. A base name in the 56-63 char window passes, while its companion silently overflows and Postgres truncates it - leaving the DB schema out of sync with what Payload thinks it created (in dev,pushthen promptsIs <table> created or renamed?on every boot).The fix
Extract the 63-char check out of
createTableNameinto a reusablevalidateIdentifierLength, and apply it at the 4 companion-table definition sites inschema/build.ts. Over-long companions now fail fast with the existing error +dbNametip:Tests & why this is the right fix
validateIdentifierLength.spec.ts: throws over 63, passes at/under.buildRawSchema.spec.ts: an overflowing_localesnow throws in-memory.test/databaseon Postgres: 154 passed, 0 failed (no fixture relied on truncation).It's one shared validator reused everywhere a final identifier is produced - no duplication - and it turns Postgres's silent truncation into an explicit, actionable error, matching how base names already behave. Arrays/blocks funnel through the same
buildTablechoke point, so those 4 sites cover the whole class without touchingtraverseFields.ts.