Better Auth in Rust

Errors

Error types, HTTP status codes, and error response format.

Error Response Format

All errors return JSON:

{
  "message": "Description of the error"
}

For 5xx errors, the actual error details are hidden and a generic message is returned to avoid leaking internal information.

AuthError Variants

VariantHTTP StatusDescription
BadRequest400Malformed request
InvalidRequest400Invalid request parameters
Validation400Input validation failed
InvalidCredentials401Wrong email/password
Unauthenticated401No valid session token
SessionNotFound401Session token not found or expired
Forbidden403Action not allowed
Unauthorized403Insufficient permissions
UserNotFound404User does not exist
NotFound404Resource not found
Conflict409Duplicate resource (email, username)
RateLimited429Too many requests
NotImplemented501Feature not implemented
Config500Configuration error
Database500Database operation failed
Serialization500JSON serialization error
Plugin500Plugin-specific error
Internal500Unexpected internal error
PasswordHash500Password hashing failure
Jwt500JWT encoding/decoding error

DatabaseError Variants

Database errors are wrapped in AuthError::Database:

VariantDescription
ConnectionFailed to connect to database
QueryQuery execution failed
MigrationMigration failed
ConstraintUnique constraint violation
TransactionTransaction failed

Programmatic Error Handling

use better_auth::error::{AuthError, AuthResult};

fn handle_result(result: AuthResult<()>) {
    match result {
        Ok(()) => println!("Success"),
        Err(e) => {
            println!("Status: {}", e.status_code());
            println!("Message: {}", e.message());
        }
    }
}

Constructors for common errors:

AuthError::bad_request("Invalid input");
AuthError::forbidden("Not allowed");
AuthError::not_found("User not found");
AuthError::conflict("Email already exists");
AuthError::internal("Unexpected error");
AuthError::validation("Password too short");
AuthError::plugin("my-plugin", "Something went wrong");
AuthError::not_implemented("Feature not available yet");

Common Error Scenarios

Authentication Errors

ErrorWhenResolution
UnauthenticatedMissing or invalid session tokenInclude a valid Authorization: Bearer <token> header or session cookie
InvalidCredentialsWrong email/password combinationCheck credentials and retry
SessionNotFoundExpired or revoked sessionRe-authenticate to get a new session

Authorization Errors

ErrorWhenResolution
ForbiddenUser lacks required role (e.g., admin)Ensure the user has the appropriate role
UnauthorizedInsufficient RBAC permissionsCheck organization role and permissions

Validation Errors

ErrorWhenResolution
ValidationRequest body fails validationCheck required fields, formats, and constraints
BadRequestMalformed or missing request dataEnsure the request matches the expected format

Resource Errors

ErrorWhenResolution
UserNotFoundReferenced user doesn't existVerify the user ID
NotFoundResource (org, member, key, etc.) not foundCheck the resource ID and ownership
ConflictEmail, username, or slug already existsUse a different value

Rate Limiting

ErrorWhenResolution
RateLimitedToo many requests in the time windowWait for retryAfter seconds before retrying

Plugin-Specific Errors

OAuth Plugin

ErrorWhen
BadRequest("Unknown provider")Provider name not registered
BadRequest("Missing code parameter")OAuth callback missing authorization code
BadRequest("Provider mismatch")State provider doesn't match callback provider
Conflict("Social account already linked")Provider account linked to another user

Two-Factor Plugin

ErrorWhen
NotFound("Two-factor authentication not enabled")2FA not set up for user
BadRequest("Invalid backup code")Backup code doesn't match
BadRequest("No backup codes available")All backup codes used

Organization Plugin

ErrorWhen
Forbidden("Insufficient permissions")Role lacks required RBAC permission
Conflict("Slug already taken")Organization slug already in use

Passkey Plugin

ErrorWhen
NotImplemented(...)allow_insecure_unverified_assertion is false
BadRequest("Invalid or expired ... challenge")Challenge expired or already used

Error Handling in Axum

When using the Axum integration, AuthError is automatically converted to an HTTP response:

use axum::{Json, response::IntoResponse};
use better_auth::error::AuthError;

async fn my_handler() -> Result<impl IntoResponse, AuthError> {
    // AuthError automatically becomes the right HTTP status + JSON body
    Err(AuthError::bad_request("Something went wrong"))
}

On this page