fix(connection): surface real IO error instead of 'db error' on connect failure#708
fix(connection): surface real IO error instead of 'db error' on connect failure#708
Conversation
…ct failure Walk the tokio-postgres error source chain to find the actual underlying cause (IO error, DNS failure, etc.) when the top-level message is the opaque 'db error' / 'error connecting to server' placeholder. Before: connection to server at "localhost", port 9999 failed: db error After: connection to server at "localhost", port 9999 failed: Connection refused (os error 111) Fixes #707
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #708 +/- ##
==========================================
+ Coverage 68.83% 68.84% +0.01%
==========================================
Files 46 46
Lines 30852 30870 +18
==========================================
+ Hits 21234 21251 +17
- Misses 9618 9619 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…password also shows real error
REV Review — PR #708: fix(connection): surface real IO errorSummary
Blocking findingsNone. Non-blocking findingssrc/connection.rs — source-chain walk always takes the deepest non-generic error The loop updates while let Some(src) = cause {
let s = src.to_string();
if !s.is_empty() && s != "db error" && … {
found = s; // keeps overwriting — deepest wins
}
cause = src.source();
}In tokio-postgres error chains the ordering is typically: Taking the deepest node works well for OS errors but could strip away a more descriptive mid-chain message if the chain is longer than two levels. For authentication failures in particular, the postgres Suggestion: if the intended semantics are "deepest wins", add a comment. If "first informative" is intended, use src/connection.rs — hardcoded sentinel strings are fragile The three sentinel strings ( CLAUDE.md — security rules added without HISTORY entry The new Potential issuesInfinite loop if a source chain is circular
let mut depth = 0usize;
while let Some(src) = cause {
if depth > 10 { break; }
depth += 1;
…
}"error communicating with the server" sentinel scope
Test coverageNo tests were added for the changed logic in Missing test scenarios:
Overall: test coverage for the new logic is absent. Since the function is internal and the existing tests are integration-style (requiring a real or mock Postgres), a unit-test helper that accepts a Severity: MEDIUM — the new code path is exercised only in production. VerdictAPPROVE The fix is correct, minimal, and addresses a real UX pain point (opaque "db error" messages). The non-blocking findings are worth addressing in a follow-up: add a depth guard, document the "deepest wins" semantics, and add at least one unit test for the source-chain walk. No blocking issues. |
|
Thanks! |
Fixes #707
Problem
Users got
connection failed: db errorwith no useful information. Reported by @mlusetti on X.Root cause
tokio_postgres::Error::to_string()returns the opaque string"db error"/"error connecting to server"when the error is not a DB-level error. The actual IO error (TCP refused, DNS failure, etc.) is buried in thesource()chain.Fix
Walk the
std::error::Error::source()chain inmap_connect_error()to find the deepest meaningful message.Before / After