Structured Errors
Requires the
duckdb-1-5feature flag (DuckDB 1.5.0+).
ErrorData is an RAII wrapper around DuckDB's duckdb_error_data handle — the
structured error type returned by several DuckDB 1.5 C API surfaces. Unlike a
bare error string, an ErrorData carries both a human-readable message and a
machine-readable category (DuckDbErrorType), so your extension can branch
on the kind of failure (for example, distinguishing Io from OutOfMemory).
It is the common currency of the other 1.5 modules: Expression::fold,
the virtual file system, and the appender all
report failures as an ErrorData.
Inspecting an error
#![allow(unused)] fn main() { use quack_rs::error_data::{DuckDbErrorType, ErrorData}; fn handle(err: ErrorData) { if err.has_error() { match err.error_type() { DuckDbErrorType::Io => eprintln!("I/O failure"), DuckDbErrorType::OutOfMemory => eprintln!("out of memory"), other => eprintln!("{other:?}: {}", err.message().unwrap_or_default()), } } } }
Constructing an error
Build a structured error to hand back to DuckDB (for example from a callback):
#![allow(unused)] fn main() { use quack_rs::error_data::{DuckDbErrorType, ErrorData}; let err = ErrorData::new(DuckDbErrorType::InvalidInput, "row index out of range"); assert!(err.has_error()); assert_eq!(err.error_type(), DuckDbErrorType::InvalidInput); }
Propagating with ?
into_extension_error converts an ErrorData into the SDK's ExtensionError,
so a structured DuckDB error can flow through the ? operator in your
registration or callback logic:
#![allow(unused)] fn main() { use quack_rs::error::ExtensionError; use quack_rs::file_system::{FileOpenOptions, FileSystem}; use quack_rs::client_context::ClientContext; fn read_header(ctx: &ClientContext) -> Result<(), ExtensionError> { let fs = FileSystem::from_client_context(ctx) .ok_or_else(|| ExtensionError::new("no file system"))?; let handle = fs .open(c"data.bin", &FileOpenOptions::read_only()) .map_err(ErrorData::into_extension_error)?; let _ = handle; Ok(()) } }
API
| Item | Description |
|---|---|
ErrorData::new(error_type, message) | Construct a structured error |
ErrorData::from_raw(raw) (unsafe) | Take ownership of a raw duckdb_error_data |
has_error() | true if the handle represents an actual error |
error_type() | The DuckDbErrorType category |
message() | Option<String> — the error text |
into_extension_error() | Consume into an ExtensionError |
is_null() / as_raw() / into_raw() | Handle inspection / escape hatches |
DuckDbErrorType is a #[non_exhaustive] enum mirroring duckdb_error_type
(Io, OutOfMemory, Conversion, Catalog, Constraint, Permission, …).
Unknown or future categories map to DuckDbErrorType::Invalid.
UTF-8 validation
The free function check_valid_utf8 exposes DuckDB's own UTF-8 validator, which
is stricter than Rust's in some cases. Use it to validate externally-sourced
bytes before handing them to DuckDB string APIs:
#![allow(unused)] fn main() { use quack_rs::error_data::check_valid_utf8; fn demo(bytes: &[u8]) { match check_valid_utf8(bytes) { Ok(()) => { /* safe to pass to DuckDB */ } Err(err) => eprintln!("invalid UTF-8: {}", err.message().unwrap_or_default()), } } }
Ownership
ErrorData calls duckdb_destroy_error_data on drop. When you receive one from
a fallible 1.5 API, it owns the handle — just let it drop, or call
into_extension_error() / into_raw() to move the data out.
Related modules
- Bound Expressions —
Expression::foldreturnsErrorData - Virtual File System — file operations return
ErrorData - Bulk Appender —
Appender::error_datareturnsErrorData - Error Handling — the SDK's primary
ExtensionErrortype