fix(migrations): propagate GBRAIN_DATABASE_URL + GBRAIN_DISABLE_DIRECT_POOL to migration subprocesses (IPv6 band-aid)#1005
Conversation
…T_POOL to subprocess env
Migration orchestrators spawn child processes via execSync with
`env: process.env`. On machines where the database URL is a Supabase
Session Pooler (port 6543), connection-manager.ts auto-derives a
direct URL (`db.<ref>.supabase.co:5432`) for DDL operations. That
hostname is IPv6-only on many networks, causing ECONNREFUSED in every
migration subprocess.
Each orchestrator now calls _childEnv() which:
1. Reads ~/.gbrain/config.json to guarantee GBRAIN_DATABASE_URL
is set to the configured pooler URL in child env
2. Sets GBRAIN_DISABLE_DIRECT_POOL=1 to suppress direct-URL
derivation in the child process connection-manager
Affected: v0.11.0, v0.12.0, v0.12.2, v0.13.0, v0.16.0, v0.18.0,
v0.18.1, v0.21.0, v0.29.1
Repro: Supabase Session Pooler (port 6543), IPv4-only or
IPv4-preferred network, run `gbrain apply-migrations --yes`.
All orchestrator-spawned subprocesses fail with ECONNREFUSED
against db.<ref>.supabase.co:5432.
See: garrytan/gstack#1301
Note: This is a band-aid. The principled fix is to not derive a
direct URL at all when the primary URL is already a Session Pooler
(port 6543), since Session Pooler supports DDL natively. See
companion PR on connection-manager.ts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thanks for this contribution — and apologies for the slow triage. We did a full pass over the entire PR backlog. gbrain has moved fast, and the maintainer's larger "cathedral" rewrites have superseded a big share of community PRs: the AI gateway + recipes + user_provided_models system replaced almost all individual provider PRs; #1805 fixed the whole Postgres module-singleton class; #1542 unified the type taxonomy; #1657 the retrieval path; #1802 the doctor; and so on. We're closing this one in that cleanup — either the fix already landed on master, it duplicates another PR or merged change, or it's outside the current merge bar. Where a closed PR carried a genuinely valuable idea, we've recorded it in docs/designs/COMMUNITY_IDEAS.md so nothing good is lost (a few may graduate into TODOs). Please don't read the close as a judgment of the work — thank you for contributing. If you believe the underlying issue is still live on the latest master, reopen with a quick note and we'll take another look. 🙏 |
Problem
gbrain apply-migrations --yesfails on networks where Supabase's direct connection (db.<ref>.supabase.co:5432) is IPv6-only — which is the default for most Supabase projects.Root cause chain
connection-manager.ts:deriveDirectUrl()detects a pooler URL and auto-derivesdb.<ref>.supabase.co:5432for DDL operationsapply-migrations.tsruns orchestrators; orchestrators spawn child subprocesses viaexecSync('gbrain init --migrate-only', { env: process.env })process.env— but this may not containGBRAIN_DATABASE_URL(it was loaded from~/.gbrain/config.jsonat parent startup, not re-exported to env)connection-manager.tsderives the IPv6-only direct URL, andddl()calls fail withECONNREFUSEDRepro
gbrain apply-migrations --yes→ ECONNREFUSED on all orchestrator-spawned subprocessesRelated: garrytan/gstack#1301
See also: garrytan/gstack#1249 (similar IPv6-avoidance pattern in browse module)
This fix (band-aid)
Add
_childEnv()to each migration orchestrator that:~/.gbrain/config.json→ guaranteesGBRAIN_DATABASE_URLis the pooler URL in child envGBRAIN_DISABLE_DIRECT_POOL=1→ suppressesderiveDirectUrl()in the child'sconnection-managerFiles changed: v0.11.0, v0.12.0, v0.12.2, v0.13.0, v0.16.0, v0.18.0, v0.18.1, v0.21.0, v0.29.1
Why this is a band-aid
_childEnv()is duplicated across 9 filesGBRAIN_DISABLE_DIRECT_POOL=1is a blunt instrument (affects ALL operations in the child, not just DDL)The principled fix
deriveDirectUrl()should not derive a direct URL when the primary URL is already a Session Pooler (port 6543). Session Pooler maintains session state and supports DDL natively — the whole reason for the dual-pool architecture was to work around Transaction Pooler's statelessness and 2-minute statement timeout. Session Pooler has neither of those constraints.A companion PR with that 4-line fix to
connection-manager.tsmakes this 126-line band-aid unnecessary.Happy to PR the band-aid fix if useful
Verified working on:
aws-1-ap-northeast-1.pooler.supabase.com)