pgx icon indicating copy to clipboard operation
pgx copied to clipboard

`normalizeTimeoutError` is overwriting dial error

Open mbrancato opened this issue 3 months ago • 1 comments

Describe the bug I'm using a proxying driver here for Google CloudSQL. I'm trying to handle some errors in a way that provides a clear reason to the user.

When it attempts to dial here: https://github.com/jackc/pgx/blob/61d3c965ad442cc14d6b0e39e0ab3821f3684c03/pgconn/pgconn.go#L320

I get a DialError that wraps an net.OpError that wraps a poll.DeadlineExceededError: i/o timeout. And that error has useful information about what is going on behind the scenes. It looks like this:

Image

However, this is passed to newPerDialConnectError and then normalizeTimeoutError. And eventually hands here: https://github.com/jackc/pgx/blob/61d3c965ad442cc14d6b0e39e0ab3821f3684c03/pgconn/errors.go#L145

Which drops the useful error and loses all useful information.

Is there a way to wrap this error so that useful information isn't lost downstream?

Interestingly, its not hitting my context timeout - in fact my context is dropped and that at least partially seems to be due to how database/sql drops the context here: https://github.com/golang/go/blob/ac803b5949f6dbc5bfa559afe506d35f9e1b3195/src/database/sql/sql.go#L809 And then pgx generates a new context here: https://github.com/jackc/pgx/blob/61d3c965ad442cc14d6b0e39e0ab3821f3684c03/stdlib/sql.go#L325

So ultimately

To Reproduce I don't have a full, runnable example, but this is the entrypoint back to pgx

	db, err := sql.Open(sqlDriverPostgresIam, dsn)
	if err != nil {
		return fmt.Errorf("failed to open database connection: %w", err)
	}

	var result int
	err = db.QueryRowContext(ctx, "SELECT 1").Scan(&result)

Expected behavior I'd like to return information from the upstream error, which has information on the IP that it cannot connect to, etc.

Actual behavior I'm getting a less useful and even confusing error about failing to connect to localhost, which is just the proxy part of the driver.

Version

  • Go: go version go1.24.7 darwin/arm64
  • PostgreSQL: 17
  • pgx: v5.7.6

Additional context Driver: https://github.com/GoogleCloudPlatform/cloud-sql-go-connector/blob/main/postgres/pgxv5/postgres.go

mbrancato avatar Sep 14 '25 22:09 mbrancato

I think this is actually working as designed. The underlying poll.DeadlineExceededError: i/o timeout is an implementation detail. pgx uses SetDeadline to interrupt connections when a context is canceled. normalizeTimeoutError so the caller gets a context error rather than whatever underlying error bubbled up from the interrupted net operation.

My guess is that 60 second failsafe context is being triggered.

jackc avatar Sep 29 '25 12:09 jackc