Skip to content

fix(sql): don't treat URL pathname as Unix socket path#27714

Open
robobun wants to merge 3 commits intomainfrom
claude/fix-sql-url-path-27713
Open

fix(sql): don't treat URL pathname as Unix socket path#27714
robobun wants to merge 3 commits intomainfrom
claude/fix-sql-url-path-27713

Conversation

@robobun
Copy link
Collaborator

@robobun robobun commented Mar 3, 2026

Summary

  • Fix Bun SQL treating the URL path component (database name) as a Unix domain socket path, causing FailedToOpenSocket for any standard Postgres/MySQL connection URL
  • Only use url.pathname as the socket path for unix:// protocol URLs; for postgres://, mysql://, etc., the pathname is the database name, not a socket path

Root cause

In src/js/internal/sql/shared.ts, the line:

path ||= options.path || url.pathname;

was extracting url.pathname (e.g. /mydb from postgres://user:pass@host:5432/mydb) and setting it as the Unix socket path. The native Zig code sees a non-empty path and uses connectUnixAnon() instead of TCP, resulting in FailedToOpenSocket or ECONNREFUSED when the database name happens to match an existing filesystem path (common in Docker/Kubernetes environments).

Fix

Only use url.pathname as the socket path when url.protocol === "unix:". For all other protocols, the pathname is the database name.

Test plan

  • New regression test test/regression/issue/27713.test.ts with 7 test cases
  • Test verifies path is not set from URL pathname for postgres/mysql URLs
  • Test verifies unix:// protocol still correctly uses pathname as socket path
  • Test fails with USE_SYSTEM_BUN=1 (system Bun 1.3.10) and passes with debug build
  • Existing adapter-env-var-precedence.test.ts (38 tests) all pass
  • Existing sqlite-url-parsing.test.ts (176 tests) all pass

Closes #27713

🤖 Generated with Claude Code

When parsing a Postgres/MySQL connection URL like
`postgres://user:pass@host:5432/mydb`, the URL pathname `/mydb`
(the database name) was incorrectly assigned to the `path` variable
used for Unix domain socket connections. This caused the native code
to attempt a Unix socket connection to `/mydb` instead of TCP,
resulting in FailedToOpenSocket.

Only use `url.pathname` as the socket path when the protocol is
`unix://`. For all other protocols (postgres://, mysql://, etc.),
the pathname is the database name and should not be used as a
socket path.

Fixes #27713

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions bot added the claude label Mar 3, 2026
@robobun
Copy link
Collaborator Author

robobun commented Mar 3, 2026

Updated 5:47 AM PT - Mar 3rd, 2026

❌ Your commit bf42798d has 2 failures in Build #38583 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 27714

That installs a local version of the PR into your bun-27714 executable, so you can run:

bun-27714 --bun

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 3, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d7616e1 and 3cd29a9.

📒 Files selected for processing (1)
  • test/regression/issue/27713.test.ts

Walkthrough

Selects Unix socket path only for unix: URLs; for other protocols (e.g., postgres:, mysql:) the URL pathname is no longer treated as a Unix socket path—path is set only from explicit options. Adds regression tests to verify this behavior.

Changes

Cohort / File(s) Summary
Core Fix
src/js/internal/sql/shared.ts
Adjusts socket path logic: use URL pathname as socket path only when protocol is unix:; for other protocols, do not derive path from URL pathname (use options.path only).
Regression Tests
test/regression/issue/27713.test.ts
Adds tests ensuring Postgres/MySQL URLs with database names are not interpreted as Unix socket paths; covers URL strings, options objects, env DATABASE_URL, filesystem-path edge case, and windows/unix protocol conditions.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(sql): don't treat URL pathname as Unix socket path' directly summarizes the main change: preventing URL pathname from being incorrectly used as a Unix socket path.
Description check ✅ Passed The PR description comprehensively covers the root cause, fix, and test plan with clear examples and verification steps, aligning well with the required template sections.
Linked Issues check ✅ Passed The PR fully addresses issue #27713 objectives: fixes URL pathname handling to treat it as socket path only for unix:// protocol, adds comprehensive regression tests, and verifies existing tests still pass.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing issue #27713: the shared.ts modification addresses the root cause, and the new test file specifically validates the fix with no extraneous changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/regression/issue/27713.test.ts`:
- Around line 122-131: The test "unix:// protocol should still use pathname as
socket path" uses a fixed socket path ("/tmp/bun-test-27713.sock") which can
collide across runs; change the setup in the test around the Bun.listen call and
the sock variable to generate a unique per-run socket path (e.g., use
os.tmpdir() + a unique suffix via process.pid/timestamp or crypto.randomUUID)
and pass that generated path to Bun.listen and to new SQL(`unix://${sock.unix}`)
(references: test name, variable sock, Bun.listen, and SQL constructor) and
ensure the test cleans up the socket after completion to avoid stale files.
- Around line 34-51: The afterAll cleanup in the test currently iterates over
and mutates all environment variables (using process.env, Bun.env,
import.meta.env and originalEnv), causing cross-test coupling; restrict
restoration/cleanup to only the SQL-related keys by using the SQL_ENV_VARS list:
in the afterAll handler, remove the loops that delete/restore every key and
instead iterate only over SQL_ENV_VARS to delete those keys from process.env,
Bun.env, and import.meta.env, and restore only keys present in originalEnv for
those same SQL_ENV_VARS (referencing afterAll, SQL_ENV_VARS, originalEnv,
process.env, Bun.env, import.meta.env to locate the changes).

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6c7e972 and d7616e1.

📒 Files selected for processing (2)
  • src/js/internal/sql/shared.ts
  • test/regression/issue/27713.test.ts

- Restrict afterAll env cleanup to only SQL_ENV_VARS instead of
  wiping all environment variables, preventing cross-test coupling
- Use unique per-run socket path with process.pid suffix to avoid
  collisions across parallel test runs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — straightforward fix correctly scoping url.pathname as a socket path to only unix:// protocol URLs, with solid regression test coverage.

Extended reasoning...

Overview

This PR fixes a bug where url.pathname (the database name in standard connection URLs like postgres://user:pass@host:5432/mydb) was being incorrectly used as a Unix domain socket path. The fix is a single conditional in src/js/internal/sql/shared.ts (lines 620-627) that only assigns url.pathname to path when url.protocol === "unix:". A new regression test file with 7 test cases covers postgres URLs, mysql URLs, DATABASE_URL env var, and the unix:// protocol.

Security risks

No security risks. The change is purely about correct connection routing — it prevents TCP connections from being misrouted as Unix socket connections, which was causing connection failures rather than any data exposure.

Level of scrutiny

This is production-critical code (SQL connection parsing), but the change is minimal and well-isolated. The before/after behavior is clear: previously path ||= options.path || url.pathname for all protocols; now url.pathname only feeds into path for unix: protocol. The logic is straightforward and the test coverage validates all the key scenarios.

Other factors

The one bug report filed is pre-existing — the database name fallback using url.pathname for unix:// URLs was not introduced by this PR and has limited practical impact since unix:// users typically specify database explicitly. The PR description is thorough, existing test suites pass, and the fix aligns with how other SQL client libraries handle URL parsing.

Comment on lines +620 to +627
// Only use url.pathname as the Unix socket path for unix:// URLs.
// For postgres://, mysql://, etc., the pathname is the database name (e.g. "/mydb"),
// not a socket path. Using it as the socket path causes FailedToOpenSocket (#27713).
if (url.protocol === "unix:") {
path ||= options.path || url.pathname;
} else {
path ||= options.path;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟣 Pre-existing issue: For unix:// URLs, the database resolution fallback at line 732 still uses decodeIfValid((url?.pathname ?? "").slice(1)) without a unix: protocol guard. This means new SQL("unix:///var/run/postgresql", { adapter: "postgres" }) without an explicit database option would incorrectly set the database name to "var/run/postgresql". Consider adding the same url.protocol === "unix:" guard used for path (line 623) to the database fallback.

Extended reasoning...

What the bug is

The PR correctly fixes the path variable so that url.pathname is only used as a Unix socket path for unix:// protocol URLs (line 623). However, further down in the function, the database name resolution for postgres (line 732), mysql (line 743), and mariadb still uses decodeIfValid((url?.pathname ?? "").slice(1)) as a fallback for all protocols, including unix:.

Concrete example

Consider: new SQL("unix:///var/run/postgresql", { adapter: "postgres" })

  1. The URL is parsed: url.protocol = "unix:", url.pathname = "/var/run/postgresql"
  2. The PR correctly sets path = "/var/run/postgresql" (the socket path) because url.protocol === "unix:"
  3. When resolving the database name at line 727-733, the fallback chain is evaluated:
    • options.database is undefined
    • options.db is undefined
    • env.PG_DATABASE is undefined
    • env.PGDATABASE is undefined
    • decodeIfValid("/var/run/postgresql".slice(1)) evaluates to "var/run/postgresql"this is the bug
  4. The database name is set to "var/run/postgresql", which is the socket path minus the leading slash, not a valid database name.

Why existing code does not prevent it

The url.protocol === "unix:" guard was only added to the path resolution (line 623), not to the database resolution (lines 725-745). The database fallback chain unconditionally reads url.pathname regardless of protocol.

Impact

In practice, most users of unix:// URLs will explicitly specify a database option, which short-circuits the fallback chain. However, if they omit it, they will get a confusing connection error about a non-existent database named after their socket path. The practical impact is limited but the inconsistency with the path fix is worth addressing.

How to fix

Add a similar url.protocol === "unix:" guard to the database resolution. For example, replace decodeIfValid((url?.pathname ?? "").slice(1)) with (url?.protocol !== "unix:" ? decodeIfValid((url?.pathname ?? "").slice(1)) : null) in all three adapter cases (postgres at line 732, mysql at line 743, mariadb).

Pre-existing status

This is a pre-existing issue. The database resolution code at lines 725-745 was not modified by this PR. The url.pathname fallback for database names has always applied to all protocols. However, since this PR makes unix:// URLs more functional by fixing the socket path issue, it creates a natural place to also address this related problem. As one verifier noted, the typical unix:// usage pattern involves explicitly specifying the database option, so the practical impact is limited.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — clean, targeted fix with good test coverage.

Extended reasoning...

Overview

This PR fixes a bug where url.pathname (the database name portion of a connection URL like postgres://user:pass@host:5432/mydb) was being incorrectly assigned as a Unix socket path. The fix is a single conditional change in src/js/internal/sql/shared.ts that only uses url.pathname as the socket path when url.protocol === "unix:". A new regression test file with 7 test cases validates the fix.

Security risks

No security risks. The change actually fixes a connectivity issue — it prevents the SQL driver from attempting Unix domain socket connections when TCP was intended. No auth, crypto, or permissions code is touched.

Level of scrutiny

This is production-critical code (SQL connection handling), but the change itself is minimal and mechanical — a single if/else guard around an existing assignment. The logic is straightforward: for unix: protocol, use url.pathname as socket path; for everything else, don't. The risk of regression is low and mitigated by the comprehensive test suite.

Other factors

  • The CodeRabbit bot's nit comments (env cleanup scoping, unique socket path) were addressed in commit 3cd29a9
  • My previous pre-existing issue comment about the database fallback for unix: URLs is orthogonal to this fix and doesn't block it
  • Existing test suites (adapter-env-var-precedence, sqlite-url-parsing) reportedly pass
  • The bug hunting system found no issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bun SQL treats Postgres URL path as Unix socket path, causing FailedToOpenSocket on any URL with a database name

1 participant