diff --git a/CHANGELOG.md b/CHANGELOG.md index a387cc64..c8c744d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If ## Fixed - DANE: Treat DNSSEC `bogus` as a temporary failures to prevent downgrade attacks. - OIDC: `ECDSA` private key support for `SEC1` format. +- PostgreSQL: Include error chain in error messages. ## [0.16.11] - 2026-06-25 diff --git a/crates/store/src/backend/postgres/mod.rs b/crates/store/src/backend/postgres/mod.rs index 10572032..ed8fa7b0 100644 --- a/crates/store/src/backend/postgres/mod.rs +++ b/crates/store/src/backend/postgres/mod.rs @@ -27,7 +27,7 @@ pub struct PostgresStore { #[inline(always)] fn into_error(err: tokio_postgres::error::Error) -> trc::Error { - let mut local_err = trc::StoreEvent::PostgresqlError.reason(err.to_string()); + let mut local_err = trc::StoreEvent::PostgresqlError.reason(error_chain(&err)); if let Some(db_err) = err.as_db_error() { local_err = local_err.code(db_err.code().code().to_string()); if let Some(detail) = db_err.detail() { @@ -41,9 +41,26 @@ fn into_error(err: tokio_postgres::error::Error) -> trc::Error { local_err } +fn error_chain(err: &(dyn std::error::Error + 'static)) -> String { + let mut message = err.to_string(); + let mut source = err.source(); + while let Some(cause) = source { + let cause_message = cause.to_string(); + if !cause_message.is_empty() && !message.ends_with(&cause_message) { + message.push_str(": "); + message.push_str(&cause_message); + } + source = cause.source(); + } + message +} + #[inline(always)] fn into_pool_error(err: deadpool_postgres::PoolError) -> trc::Error { - trc::StoreEvent::PostgresqlError.reason(err) + match err { + deadpool_postgres::PoolError::Backend(err) => into_error(err), + err => trc::StoreEvent::PostgresqlError.reason(error_chain(&err)), + } } impl SearchIndex {