fix: Postgres ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE under concurrent load (#284)#288
Conversation
…ace (#284) Bun's native Postgres driver has a known concurrency bug class (oven-sh/bun#16774) where queries sharing a pooled connection under load can misattribute a cached statement's column metadata, corrupting binary integer decoding and throwing ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE. Disable named prepared statement caching by default (opt back in via BETTER_CCFLARE_DB_PG_PREPARE=true) and add a retry-once safety net on the read paths (query/get) as a self-healing fallback.
Greptile SummaryThis PR mitigates intermittent Postgres integer decode failures under concurrent load. The main changes are:
Confidence Score: 5/5This looks safe to merge.
|
| Filename | Overview |
|---|---|
| packages/database/src/database-operations.ts | Adds explicit Postgres prepare-mode handling so named prepared statements are disabled unless BETTER_CCFLARE_DB_PG_PREPARE is exactly true. |
| packages/database/src/adapters/bun-sql-adapter.ts | Adds a retry-once wrapper for ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE and applies it to PostgreSQL read paths. |
| packages/database/src/adapters/tests/bun-sql-adapter-pg-integer-retry.test.ts | Adds Bun tests for successful retry, retry limit, and non-matching error behavior. |
Reviews (2): Last reviewed commit: "fix: correct inverted default for BETTER..." | Re-trigger Greptile
Review: fix: Postgres ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE under concurrent load (#284)Solid, well-scoped fix. Both mitigations (disabling named prepared statements + retry-once on the specific error code) are reasonable defense-in-depth for a driver-level race, and the change is correctly confined to read paths. Code quality
Potential issues / things to watch
Test coverage
SecurityNo concerns — no new user input paths, the retry only re-issues the same already-parameterized query, and the env var is a boolean trust-the-operator switch consistent with existing ones. VerdictLooks safe to merge. The two items above (silent |
pgPrepare used `!== "true"`, which defaulted to `true` (prepared statements enabled) whenever the env var was unset, and disabled them only when explicitly set to "true" — backwards from the intended "disabled by default, opt in via BETTER_CCFLARE_DB_PG_PREPARE=true". This left the ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE concurrency path (#284) reachable under normal Postgres load with no env override set.
|
Fixed in d60bd19 — |
Summary
Fixes #284 — Postgres-backed deployments intermittently throw
ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZEwhile loading account data.Root cause: Bun's native Postgres driver has a known concurrency bug class (oven-sh/bun#16774) where queries sharing a pooled connection under concurrent load can misattribute a cached statement's column metadata, corrupting binary integer decoding. This isn't a better-ccflare schema or query bug — confirmed no
NUMERIC/DECIMALcolumns and noRETURNINGclauses are involved in the crash path.Two mitigations, both agreed as defense-in-depth:
prepare: falseon the BunSQLclient) — unnamed prepared statements don't persist across queries, closing the window for cross-query metadata contamination. Operators can opt back in viaBETTER_CCFLARE_DB_PG_PREPARE=true.BunSqlAdapterfor the specificERR_POSTGRES_UNSUPPORTED_INTEGER_SIZEerror code, scoped to the read paths (query()/get()) since DML (run()/runWithChanges()) never decodes column binary data here (noRETURNINGclauses).Test plan
packages/databasetest suite passes (159 existing tests)bun run lint && bun run typecheck && bun run format— clean (pre-existing unrelated warnings only)detect_changesconfirms LOW risk — change is transparent to all callers (repositories, stats, alerts, handlers), no behavior change for successful queries