---
import DocsLayout from '../../layouts/DocsLayout.astro';
import CodeBlock from '../../components/CodeBlock.astro';
const basicHandling = `use prax_query::{QueryError, ErrorCode};
// Handle specific error types
match result {
Ok(user) => println!("Found user: {:?}", user),
Err(e) if e.is_not_found() => {
println!("User not found");
}
Err(e) if e.is_constraint_violation() => {
println!("Constraint violated: {}", e.message);
}
Err(e) if e.is_timeout() => {
println!("Query timed out");
}
Err(e) if e.is_retryable() => {
println!("Transient error, retrying...");
// Retry logic
}
Err(e) => {
println!("Error [{}]: {}", e.code, e.message);
}
}`;
const errorCodes = `// Error codes follow the Pxxxx format
// Query Errors (P1xxx)
ErrorCode::RecordNotFound // P1001
ErrorCode::NotUnique // P1002
ErrorCode::InvalidFilter // P1003
ErrorCode::RequiredFieldMissing // P1005
// Constraint Errors (P2xxx)
ErrorCode::UniqueConstraint // P2001
ErrorCode::ForeignKeyConstraint // P2002
ErrorCode::NotNullConstraint // P2004
// Connection Errors (P3xxx)
ErrorCode::ConnectionFailed // P3001
ErrorCode::PoolExhausted // P3002
ErrorCode::AuthenticationFailed // P3004
// Transaction Errors (P4xxx)
ErrorCode::Deadlock // P4002
ErrorCode::SerializationFailure // P4003
// Query Execution (P5xxx)
ErrorCode::QueryTimeout // P5001
ErrorCode::SqlSyntax // P5002`;
const actionableErrors = `use prax_query::QueryError;
// Errors include actionable suggestions
let err = QueryError::unique_violation("User", "email");
println!("{}", err.display_full());
// Output:
// Error [P2001]: Unique constraint violated on User.email
// → Model: User
// → Field: email
//
// Suggestions:
// 1. A record with this email already exists
// 2. Use upsert() to update if exists, create if not
// \`\`\`
// client.user().upsert()
// .where(user::email::equals(value))
// .create(...)
// .update(...)
// .exec().await
// \`\`\`
//
// More info: https://prax.rs/docs/errors/P2001`;
const coloredOutput = `use prax_query::QueryError;
// Display with ANSI colors for terminal
let err = QueryError::not_found("User")
.with_context("Finding user by email")
.with_suggestion("Verify the user exists");
// Colored output for CLI tools
eprintln!("{}", err.display_colored());
// Plain text for logging
log::error!("{}", err.display_full());`;
const customContext = `use prax_query::{QueryError, ErrorCode, Suggestion};
// Add context to errors
let err = QueryError::not_found("User")
.with_context("Authenticating user login")
.with_model("User")
.with_field("email")
.with_suggestion("Check the email address is correct")
.with_code_suggestion(
"Register the user first",
"client.user().create(data! { email, password }).exec().await"
)
.with_help("Users must be registered before they can log in");
// Access error details
println!("Code: {}", err.code); // P1001
println!("Message: {}", err.message);
println!("Model: {:?}", err.context.model);
println!("Docs: {}", err.docs_url());`;
const errorChecks = `use prax_query::QueryError;
// Boolean checks for error categories
fn handle_error(err: &QueryError) {
// Record errors
if err.is_not_found() { /* ... */ }
// Constraint violations
if err.is_constraint_violation() { /* ... */ }
// Timeout errors (connection or query)
if err.is_timeout() { /* ... */ }
// Connection-related errors
if err.is_connection_error() { /* ... */ }
// Can this error be retried?
if err.is_retryable() {
// Safe to retry: timeouts, deadlocks, pool exhaustion
}
}`;
const errorMacro = `use prax_query::{query_error, ErrorCode};
// Create custom errors with the macro
let err = query_error!(
ErrorCode::InvalidParameter,
"Email format is invalid",
with_field = "email",
with_suggestion = "Use a valid email like user@example.com",
with_help = "Email must contain @ and a domain"
);`;
---
<DocsLayout title="Error Handling - Prax ORM">
<article class="max-w-4xl mx-auto px-6 py-12">
<header class="mb-12">
<h1 class="text-4xl font-bold mb-4">Error Handling</h1>
<p class="text-xl text-muted">
Prax provides comprehensive error types with unique error codes, actionable suggestions,
and helpful context to quickly diagnose and fix issues.
</p>
</header>
<nav class="mb-8 p-4 bg-surface rounded-lg border border-border">
<h3 class="text-sm font-semibold text-muted mb-2">On this page</h3>
<ul class="space-y-1 text-sm">
<li><a href="#handling" class="text-primary-400 hover:text-primary-300">Basic Handling</a></li>
<li><a href="#codes" class="text-primary-400 hover:text-primary-300">Error Codes</a></li>
<li><a href="#actionable" class="text-primary-400 hover:text-primary-300">Actionable Messages</a></li>
<li><a href="#context" class="text-primary-400 hover:text-primary-300">Adding Context</a></li>
<li><a href="#checks" class="text-primary-400 hover:text-primary-300">Error Checks</a></li>
</ul>
</nav>
<div class="space-y-12">
<section id="handling" class="mb-12">
<h2 class="text-2xl font-semibold mb-4">Basic Error Handling</h2>
<p class="text-muted mb-4">
Use pattern matching or boolean checks to handle different error types.
</p>
<CodeBlock code={basicHandling} lang="rust" filename="Error Handling" />
</section>
<section id="codes" class="mb-12">
<h2 class="text-2xl font-semibold mb-4">Error Codes</h2>
<p class="text-muted mb-4">
Every error has a unique code in the <code>Pxxxx</code> format for easy identification and documentation lookup.
</p>
<CodeBlock code={errorCodes} lang="rust" filename="Error Code Reference" />
<div class="mt-6">
<h4 class="font-semibold mb-3">Error Code Categories</h4>
<table class="w-full text-sm">
<thead>
<tr class="border-b border-border">
<th class="text-left py-2 text-muted">Range</th>
<th class="text-left py-2 text-muted">Category</th>
<th class="text-left py-2 text-muted">Description</th>
</tr>
</thead>
<tbody class="text-muted">
<tr class="border-b border-border/50">
<td class="py-2"><code>P1xxx</code></td>
<td>Query</td>
<td>Record not found, invalid filters</td>
</tr>
<tr class="border-b border-border/50">
<td class="py-2"><code>P2xxx</code></td>
<td>Constraint</td>
<td>Unique, foreign key, not null violations</td>
</tr>
<tr class="border-b border-border/50">
<td class="py-2"><code>P3xxx</code></td>
<td>Connection</td>
<td>Connection failures, pool exhausted, auth</td>
</tr>
<tr class="border-b border-border/50">
<td class="py-2"><code>P4xxx</code></td>
<td>Transaction</td>
<td>Deadlocks, serialization failures</td>
</tr>
<tr class="border-b border-border/50">
<td class="py-2"><code>P5xxx</code></td>
<td>Execution</td>
<td>Timeouts, syntax errors</td>
</tr>
<tr class="border-b border-border/50">
<td class="py-2"><code>P6xxx</code></td>
<td>Data</td>
<td>Type mismatches, serialization</td>
</tr>
<tr class="border-b border-border/50">
<td class="py-2"><code>P7xxx</code></td>
<td>Configuration</td>
<td>Invalid config, missing settings</td>
</tr>
<tr class="border-b border-border/50">
<td class="py-2"><code>P9xxx</code></td>
<td>Internal</td>
<td>Internal errors, bugs</td>
</tr>
</tbody>
</table>
</div>
</section>
<section id="actionable" class="mb-12">
<h2 class="text-2xl font-semibold mb-4">Actionable Error Messages</h2>
<p class="text-muted mb-4">
Errors include suggestions for how to fix the issue, with code examples when applicable.
</p>
<CodeBlock code={actionableErrors} lang="rust" filename="Actionable Suggestions" />
<div class="mt-6">
<h4 class="font-semibold mb-3">Colored Terminal Output</h4>
<p class="mb-4 text-muted">
Use <code>display_colored()</code> for beautiful terminal output with ANSI colors.
</p>
<CodeBlock code={coloredOutput} lang="rust" filename="Colored Output" />
</div>
</section>
<section id="context" class="mb-12">
<h2 class="text-2xl font-semibold mb-4">Adding Context</h2>
<p class="text-muted mb-4">
Enrich errors with additional context for better debugging.
</p>
<CodeBlock code={customContext} lang="rust" filename="Error Context" />
<div class="mt-6">
<h4 class="font-semibold mb-3">Error Macro</h4>
<p class="mb-4 text-muted">
Create custom errors quickly with the <code>query_error!</code> macro.
</p>
<CodeBlock code={errorMacro} lang="rust" filename="Error Macro" />
</div>
</section>
<section id="checks">
<h2 class="text-2xl font-semibold mb-4">Error Checks</h2>
<p class="text-muted mb-4">
Use boolean methods to check error categories without pattern matching.
</p>
<CodeBlock code={errorChecks} lang="rust" filename="Error Checks" />
<div class="mt-6 p-4 bg-success-500/10 border border-success-500/30 rounded-lg">
<h4 class="font-semibold text-success-400 mb-2">✓ Retryable Errors</h4>
<p class="text-sm text-muted">
The <code class="text-primary-400">is_retryable()</code> check identifies transient errors that
are safe to retry: connection timeouts, pool exhaustion, deadlocks, and serialization failures.
Use this with the <code class="text-primary-400">RetryMiddleware</code> for automatic handling.
</p>
</div>
</section>
</div>
</article>
</DocsLayout>