30 秒自检

错误堆栈出现以下任一:

  • prepared statement "s0" does not exist
  • PostgresError: prepared statement "..." does not exist
  • 错误码 26000
  • 偶发性出现(不是每次请求都报,约 10-30% 概率)

如果错误是连接超时 / SSL 失败,看其他文章。

最短处理路径

1:判断走 6543 还是 5432

Supabase 提供两个连接端口:

端口用途Mode是否支持 prepared
5432Direct Connectionsession支持
6543Pooled Connection (Supavisor)transaction不支持

Serverless 部署(Vercel / Netlify / Cloudflare Workers)必须用 6543,否则连接数瞬间打满。传统 EC2 / Render 长期连接可用 5432。

2:Prisma 修复

DATABASE_URL 加参数:

DATABASE_URL="postgresql://postgres.[ref]:[pwd]@aws-0-[region].pooler.supabase.com:6543/postgres?pgbouncer=true&connection_limit=1"
DIRECT_URL="postgresql://postgres.[ref]:[pwd]@aws-0-[region].pooler.supabase.com:5432/postgres"

schema.prisma 同时配置:

datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
  directUrl = env("DIRECT_URL")
}

DIRECT_URL 用于 migrations(必须用 session mode)。DATABASE_URL 用于运行时(pooled)。

3:Drizzle ORM 修复

import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

const client = postgres(process.env.DATABASE_URL!, {
  prepare: false, // 关键
  max: 1, // serverless 限制
});

export const db = drizzle(client);

4:node-postgres (pg) 修复

import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  // pg 不直接支持,需要换连接每次
  max: 1,
});

// 用 simple query 而不是 prepared
await pool.query({ text: 'SELECT * FROM users WHERE id = $1', values: [1] });

pg 库默认就是 simple query,但如果上层 ORM(Sequelize)用 prepared 包装就会出问题。

5:Supabase JavaScript Client

如果用 @supabase/supabase-js 直接调用,不会有这个问题(它走 PostgREST 而不是直连)。

根因

PgBouncer transaction mode 的工作机制:

  1. 客户端 A 发起事务 1,PgBouncer 分配后端连接 X。
  2. 客户端 A 在事务 1 内 prepare 一个 statement “s1”,存在连接 X。
  3. 事务 1 结束,PgBouncer 回收连接 X 给池。
  4. 客户端 A 发起事务 2,PgBouncer 分配后端连接 Y(不一定是 X)。
  5. 客户端 A 想用 “s1”,但连接 Y 没有这个 prepared statement,直接报错。

session mode 则保证客户端始终用同一个连接。

继续排查

偶尔报错,不是每次

正常。因为 transaction mode 下每个事务有独立连接分配。第一个事务 prepare 成功 → 后续如果分到不同连接就失败。

local 测试没问题,线上才报

Local 通常直连 5432,线上 serverless 走 6543。

Prisma migrations 失败

确保 DIRECT_URL 设置正确,走 5432。Prisma migrate 必须用 session mode。

如果还没恢复

试 Supavisor v2(2026 年 Q1 上线)的「prepared statement transparent forwarding」:

DATABASE_URL="...:6543/postgres?pgbouncer=true&supavisor_prepared=true"

注意:仍在 beta,不一定所有 ORM 都兼容。

跨地区访问 Supabase Dashboard

国内排查 Supabase 错误时,Dashboard 的 Logs / Database Indicators 加载缓慢,Real-time Inspector 可能断连。一条海外服务跑 GitHub Actions / Cloudflare 的稳定线路能让 Supabase Dashboard 顺畅,排查更快。

相关报错