schemainspect: constraints.sql only skips pg_temp_1, so another session's temp table crashes load_all_relations

Open Beginner friendly
#471 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
1/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
postgresql, typescript
Domain
databases

Research direction

Start with queries/pg/sql/constraints.sql at line 147 and compare its temp-schema filtering with queries/pg/sql/relations.sql and the indexes CTE. Reproduce with a temp table containing a constraint in one session, then run Migration.create from another; done means inspection completes without loading unrelated temporary-table constraints.

Written by the indexing model from the issue text.

Description

Summary

Migration.create (and any get_inspector call) throws

TypeError: Cannot read properties of undefined (reading 'constraints')
    at PostgreSQL.load_all_relations (@pgkit/schemainspect/0.6.1/dist/pg/obj.js:1321)
    at async PostgreSQL.load_all_async (.../pg/obj.js:961)
    at async Function.create (.../pg/obj.js:944)
    at async get_inspector (.../get.js:20)
    at async Function.create (@pgkit/migra/0.6.1/dist/migra.js:22)

whenever any other backend on the server holds a temp table that has a
constraint (a PRIMARY KEY, UNIQUE or CHECK). It is not about the database
being inspected — one unrelated idle session is enough to make every inspection
of that server fail.

Root cause

load_all_relations does:

for (const each of Object.values(this.constraints)) {
    const t = each.quoted_full_table_name;
    this.relations[t].constraints[each.quoted_full_name] = each;   // <-- this.relations[t] is undefined
}

The two queries that populate those maps disagree about temp schemas:

  • queries/pg/sql/relations.sql excludes them by pattern —
    n.nspname not like 'pg_temp_%' (lines 23, 65, 107 on main).

  • queries/pg/sql/constraints.sql excludes only the literal pg_temp_1
    line 147 on main:

    -- SKIP_INTERNAL and nspname not in ('pg_internal', 'pg_catalog', 'information_schema', 'pg_toast', 'pg_temp_1', 'pg_toast_temp_1')
    

pg_temp_1 is only ever the first backend's temp namespace. Any other session
gets pg_temp_2, pg_temp_75, pg_temp_156, … — all of which pass that filter.
So constraints on other sessions' temp tables are loaded, their tables are not,
and the lookup dereferences undefined.

The same file is already inconsistent with itself: the indexes CTE at line 69
does use the pattern form (schemaname not like 'pg_temp_%').

Reproduction
-- session A, and leave it open
CREATE TEMP TABLE t (id int PRIMARY KEY);
SELECT pg_sleep(600);
// session B
import { createClient } from '@pgkit/client'
import { Migration } from '@pgkit/migra'
const c = createClient(process.env.URL!)
await Migration.create(c, c, { schema: 'public' })   // throws

Terminate session A and the exact same call succeeds.

Verified against PostgreSQL 17 (Supabase), @pgkit/schemainspect 0.6.1 /
@pgkit/migra 0.6.1.

Suggested fix

Make constraints.sql line 147 use the same pattern form the other queries use:

  -- SKIP_INTERNAL and nspname not in ('pg_internal', 'pg_catalog', 'information_schema', 'pg_toast')
  -- SKIP_INTERNAL and nspname not like 'pg_temp_%' and nspname not like 'pg_toast_temp_%'

It may also be worth making load_all_relations tolerant of a missing relation
rather than throwing, since any future filter skew produces the same
hard-to-diagnose crash.

Why this is worth fixing even though it's a niche skew

This is the engine behind supabase db diff --use-migra. On a production
database it is normal for pooled backends to hold session-lifetime temp tables,
so the crash is permanent rather than intermittent — and the Supabase CLI
currently reports it as No schema changes found (filed separately), which
makes it read as a clean diff.

Dominant language
TypeScript
Stars
289
Forks
35
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from mmkal/pgkit

All issues in mmkal/pgkit

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.