From 906aef180724aac196d9554030f06cbd23c7cf53 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Thu, 11 Jun 2026 04:06:11 +0700 Subject: [PATCH] fix(database): handle PG15+ public schema CREATE privilege error in seedDrizzleHistory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In PG15+, the CREATE privilege on the public schema is revoked from non-owner roles by default. The seedDrizzleHistory function's CREATE TABLE IF NOT EXISTS for __drizzle_migrations fails with 42501, causing the gateway to crash-loop on startup. Wrap the CREATE in a try/catch for 42501 — if the table already exists (created by a prior run), we continue gracefully; otherwise re-throw. Co-Authored-By: Claude Fable 5 --- .../src/shared/database/migrate.ts | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/services/discord-gateway/src/shared/database/migrate.ts b/services/discord-gateway/src/shared/database/migrate.ts index f2df1c2..0193f5f 100644 --- a/services/discord-gateway/src/shared/database/migrate.ts +++ b/services/discord-gateway/src/shared/database/migrate.ts @@ -92,14 +92,42 @@ async function seedDrizzleHistory(client: PoolClient): Promise { "Seeding Drizzle migration history — marking first migration as already applied on this pre-existing database", ); - // Create the Drizzle tracking table and insert a row for the first migration. - await client.query(` - CREATE TABLE IF NOT EXISTS "__drizzle_migrations" ( - id SERIAL PRIMARY KEY, - hash text NOT NULL, - created_at bigint - ) - `); + // Create the Drizzle tracking table if it does not exist. + // PG15+ locks down CREATE on the public schema for non-owner roles, + // so we handle the permission error gracefully by checking if the + // table already exists (it was created by a previous migration run). + try { + await client.query(` + CREATE TABLE IF NOT EXISTS "__drizzle_migrations" ( + id SERIAL PRIMARY KEY, + hash text NOT NULL, + created_at bigint + ) + `); + } catch (createErr: unknown) { + if ( + createErr instanceof Error && + "code" in createErr && + (createErr as { code: string }).code === "42501" + ) { + // Permission denied — check if the table actually exists anyway + const existsAfter = await client.query(` + SELECT EXISTS ( + SELECT FROM information_schema.tables + WHERE table_name = '__drizzle_migrations' + ) + `); + if (existsAfter.rows[0]?.exists === true) { + logger.warn( + "CREATE TABLE __drizzle_migrations denied (42501) but table already exists — continuing", + ); + } else { + throw createErr; + } + } else { + throw createErr; + } + } // Drizzle's __drizzle_migrations table has no UNIQUE(hash) // constraint, so check manually before inserting. const alreadySeeded = await client.query(