drizzle-team / drizzle-team/drizzle-orm
[BUG]: drizzle-kit generate crashes when a table with a partial index changes schema from "" to "public"
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
### Report hasn't been filed before.
- [x] I have verified that the bug I'm about to report hasn't been filed before.
### What version of `drizzle-orm` are you using?
0.45.2
### What version of `drizzle-kit` are you using?
0.31.10
### Other packages
`pg@8.20.0`
### Describe the Bug
When a table with a **partial index** is migrated from the default schema (unqualified, `schema: ""` in the snapshot) to the `public` schema, `drizzle-kit generate` crashes. The user-visible message is also misleading: drizzle-kit catches the real error and `console.error(e)`s it, but `util.inspect` then crashes on the ZodError's internals, so the message that actually surfaces is:
```
Cannot read properties of undefined (reading 'value')
```
…with no stack and no indication of which table is at fault.
The real error (visible after patching `case "unknown_error"` in `bin.cjs` to log `e.stack` instead of relying on `util.inspect`):
```
ZodError: [
{
"code": "invalid_type",
"expected": "string",
"received": "object",
"path": [ "alteredTablesWithColumns", 0, "schema" ],
"message": "Expected string, received object"
}
]
at applyPgSnapshotsDiff (drizzle-kit/bin.cjs:28417:44)
at prepareAndMigratePg (drizzle-kit/bin.cjs:32191:42)
```
Tables that don't have a partial index migrate from unqualified to `public` without issue. Only tables with `uniqueIndex(...).where(sql\`...\`)` (or `index(...).where(...)`) trigger it.
This is the Postgres counterpart of #5593 (MSSQL Filtered Index, where the bug surfaces as invalid T-SQL). In our case it's the snapshot diff that fails before any SQL is emitted.
### Why we hit this
Related to #5359 — we have a hard requirement to schema-qualify Postgres tables (`"public"."users"` instead of `"users"`) because we're behind a PgBouncer pooler that has been handing out backends with `search_path = ''`. Unqualified queries hit 42P01 on those backends, causing intermittent outages. `pgSchema("public")` is rejected by the factory, so we construct `PgSchema` directly:
```ts
import { PgSchema } from "drizzle-orm/pg-core"
const publicSchema = new PgSchema("public")
```
Runtime works fine — `db.select(...).toSQL()` correctly emits `"public"."users"`. The `drizzle-kit generate` path is where this falls over.
### Minimal repro
Before:
```ts
import { sql } from "drizzle-orm"
import { pgTable, timestamp, uniqueIndex, uuid } from "drizzle-orm/pg-core"
export const widgetsTable = pgTable(
"widgets",
{
id: uuid("id").primaryKey().defaultRandom(),
deletedAt: timestamp("deleted_at", { mode: "string" }),
},
(t) => [uniqueIndex("idx_widgets_active").on(t.id).where(sql`${t.deletedAt} IS NULL`)],
)
```
Generate a snapshot. Then switch to:
```ts
import { sql } from "drizzle-orm"
import { PgSchema, timestamp, uniqueIndex, uuid } from "drizzle-orm/pg-core"
const publicSchema = new PgSchema("public")
export const widgetsTable = publicSchema.table(
"widgets",
{
id: uuid("id").primaryKey().defaultRandom(),
deletedAt: timestamp("deleted_at", { mode: "string" }),
},
(t) => [uniqueIndex("idx_widgets_active").on(t.id).where(sql`${t.deletedAt} IS NULL`)],
)
```
Run `drizzle-kit generate`. Crashes as above.
A table-level CHECK constraint with column references in its expression triggers the same crash on the same code path.
### Workaround
Hand-edit the latest `migrations/meta/NNNN_snapshot.json` so the affected tables already have `schema: "public"` and the column references in partial-index `where` clauses (and any CHECK `value` expressions) are pre-qualified to `"public"."widgets"."deleted_at"` etc. With both sides of the diff aligned, the buggy `alteredTablesWithColumns` path isn't entered, and `drizzle-kit generate` reports "No schema changes, nothing to migrate" — which is the correct outcome since `"public"."widgets"` and `"widgets"` are equivalent in Postgres.
### Two sub-fixes that would help
1. Handle the schema field change correctly in the snapshot diff for tables with partial indexes / CHECK constraints (i.e. don't drop into the `alteredTablesWithColumns[].schema = { ... }` shape that the Zod schema rejects).
2. Log the real `e.stack` (or at least `e.message` of the ZodError, including its `issues`) in the `case "unknown_error"` handler in `bin.cjs`, instead of relying on `util.inspect(e)`. The current behavior turns a real error into a misleading `Cannot read properties of undefined (reading 'value')` that took us a while to track down.
Contributor guide
Research direction
Reproduce the migration with the provided partial-index example, then inspect applyPgSnapshotsDiff in bin.cjs and the case "unknown_error" handler. Compare the generated snapshot diff for schema changes involving partial indexes or CHECK constraints. Done means drizzle-kit generate no longer crashes, reports the real validation error when applicable, and correctly recognizes equivalent unqualified and public-qualified tables.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- postgresql, typescript
- Domain
- cli, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100