transact-rs/sqlx · error
downcast to wrong DatabaseError type; original error: {self}
Error message
downcast to wrong DatabaseError type; original error: {self} What it means
DatabaseError::downcast_ref() (sqlx-core/src/error.rs) panics when the caller asks for a concrete database error type E but the stored error is of a different backend's type. Unlike try_downcast_ref (which returns Option), this is the infallible variant meant for code that already knows the backend; mismatch indicates a logic bug, so sqlx panics and prints the original error.
Source
Thrown at sqlx-core/src/error.rs:286
/// Returns whether the error kind is a violation of a check.
fn is_check_violation(&self) -> bool {
matches!(self.kind(), ErrorKind::CheckViolation)
}
}
impl dyn DatabaseError {
/// Downcast a reference to this generic database error to a specific
/// database error type.
///
/// # Panics
///
/// Panics if the database error type is not `E`. This is a deliberate contrast from
/// `Error::downcast_ref` which returns `Option<&E>`. In normal usage, you should know the
/// specific error type. In other cases, use `try_downcast_ref`.
pub fn downcast_ref<E: DatabaseError>(&self) -> &E {
self.try_downcast_ref().unwrap_or_else(|| {
panic!("downcast to wrong DatabaseError type; original error: {self}")
})
}
/// Downcast this generic database error to a specific database error type.
///
/// # Panics
///
/// Panics if the database error type is not `E`. This is a deliberate contrast from
/// `Error::downcast` which returns `Option<E>`. In normal usage, you should know the
/// specific error type. In other cases, use `try_downcast`.
pub fn downcast<E: DatabaseError>(self: Box<Self>) -> Box<E> {
self.try_downcast()
.unwrap_or_else(|e| panic!("downcast to wrong DatabaseError type; original error: {e}"))
}
/// Downcast a reference to this generic database error to a specific
/// database error type.
#[inline]View on GitHub (pinned to 03af8bcc57)
Solutions
- Use `try_downcast_ref::<E>()` and handle the None case instead of the panicking variant.
- Check the backend before downcasting (e.g. keep separate error-handling paths per pool type, or match on the connection/pool type).
- If using AnyPool, downcast to `any::AnyDatabaseError` style handling or use backend-specific pools where you know the error type.
Example fix
// before
let pg_err = db_err.downcast_ref::<PgDatabaseError>();
// after
if let Some(pg_err) = db_err.try_downcast_ref::<PgDatabaseError>() {
handle_pg(pg_err);
} else {
handle_generic(db_err);
} Defensive patterns
Strategy: type-guard
Type guard
fn as_pg_error(db_err: &dyn sqlx::error::DatabaseError) -> Option<&sqlx::postgres::PgDatabaseError> {
db_err.try_downcast_ref::<sqlx::postgres::PgDatabaseError>()
} Try / catch
// Downcasts are infallible-looking; use the Try variants instead of catching panics:
match db_err.try_downcast_ref::<PgDatabaseError>() {
Some(e) => handle_pg(e),
None => handle_generic(db_err),
} Prevention
- Prefer try_downcast_ref/try_downcast over the panicking variants
- Keep per-backend error handling next to the pool that produced the error
- In multi-backend code, dispatch on backend before downcasting
When it happens
Trigger: Calling `err.as_database_error().unwrap().downcast_ref::<PgDatabaseError>()` (or MySqlDatabaseError, SqliteError...) on an error produced by a different driver — e.g. handling errors from a multi-backend `AnyPool`, or a generic error-handling path shared across Postgres and MySQL pools.
Common situations: Code written for PgPool later reused with a SqlitePool or AnyPool; CI running against a different database than production; match arms that call downcast_ref without first checking which backend produced the error.
Related errors
- downcast to wrong DatabaseError type; original error: {e}
- invalid column index: {}
- unimplemented!()
- failed to close setup connection
- Could not fetch metadata
AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03).
Data as JSON: /api/errors/933c772cf2972f05.
Report an issue: GitHub.