The Auth layout error handling system provides centralized error alert display across all dashboard pages, eliminating the need for manual error handling code in individual pages.
Overview
Section titled “Overview”Error messages automatically display below the navigation bar when users are redirected due to insufficient permissions or other error conditions. The system supports both predefined error codes and custom error messages with three visual alert types.
🤖 Automatic Display
Errors display automatically—no manual error handling code needed in pages.
🎨 Three Alert Types
Error (red), Warning (orange), and Info (blue) styling for different scenarios.
📝 Predefined Codes
Common error codes have user-friendly messages built-in.
⚙️ Custom Messages
Override with custom messages via props for page-specific errors.
Quick Start
Section titled “Quick Start”Automatic Error Display
Section titled “Automatic Error Display”No code required! When users are redirected with error parameters, Auth layout automatically displays the error:
---import Auth from '#layouts/Auth.astro'import type { AnyRole } from '#utils/role-types'
// Protect page with role guardconst requiredRoles: AnyRole[] = ['admin']---
<Auth pageTitle="Admin Panel" requiredRoles={requiredRoles}> <!-- Content only visible to admins --> <!-- Unauthorized users redirected with ?error=insufficient_permissions --> <!-- Error displays automatically on destination page --></Auth>What happens:
- User lacks required role → Redirects to
/dashboard?error=insufficient_permissions - Dashboard page automatically displays: “You do not have permission to access that page.”
- Error appears below navigation bar, above page content
Custom Error Message
Section titled “Custom Error Message”Override automatic errors with custom messages:
---import Auth from '#layouts/Auth.astro'
const saveError = Astro.url.searchParams.get('save_error')---
<Auth pageTitle="Settings" errorMessage={saveError ? "Failed to save settings. Please try again." : undefined} errorType="error"> <!-- Page content --></Auth>Predefined Error Codes
Section titled “Predefined Error Codes”The system includes predefined error messages for common scenarios:
| Error Code | Message |
|---|---|
insufficient_permissions | ”You do not have permission to access that page.” |
session_expired | ”Your session has expired. Please sign in again.” |
invalid_request | ”The request was invalid. Please try again.” |
not_found | ”The requested resource was not found.” |
Usage:
// In API endpoint or middlewareconst redirectUrl = new URL('/dashboard', Astro.url.origin)redirectUrl.searchParams.set('error', 'session_expired')return Astro.redirect(redirectUrl.toString())
// User sees: "Your session has expired. Please sign in again."Alert Types
Section titled “Alert Types”Control the visual style with errorType prop:
Use for: Critical errors, access denied, authentication failures
<Auth pageTitle="Admin Panel" errorMessage="Access denied. Admin privileges required." errorType="error"> <!-- Content --></Auth>Visual: Red background, red border, dark red text
Use for: Non-critical issues, deprecation notices, temporary limitations
<Auth pageTitle="Settings" errorMessage="Some features are temporarily unavailable." errorType="warning"> <!-- Content --></Auth>Visual: Yellow background, orange border, brown text
Use for: Success messages, informational alerts, status updates
<Auth pageTitle="Profile" errorMessage="Your profile has been updated successfully." errorType="info"> <!-- Content --></Auth>Visual: Blue background, blue border, dark blue text
Error Resolution Priority
Section titled “Error Resolution Priority”When multiple error sources are present, the system resolves in this order:
- Custom
errorMessageprop (highest priority) - Predefined error code mapping (from URL
?error=...) - Raw error parameter value (fallback for unknown codes)
- No error (when neither prop nor param present)
Example:
---// URL: /dashboard?error=insufficient_permissions// But page also has custom error prop---
<Auth pageTitle="Dashboard" errorMessage="Custom error message" errorType="warning"> <!-- Custom message displays, not URL param message --></Auth>Common Patterns
Section titled “Common Patterns”Pattern 1: Role Guard Errors (Automatic)
Section titled “Pattern 1: Role Guard Errors (Automatic)”---import Auth from '#layouts/Auth.astro'import type { AnyRole } from '#utils/role-types'
const requiredRoles: AnyRole[] = ['team_manager']---
<Auth pageTitle="Team Management" requiredRoles={requiredRoles}> <!-- Unauthorized access automatically redirects with error --></Auth>Pattern 2: Form Validation Errors
Section titled “Pattern 2: Form Validation Errors”---import Auth from '#layouts/Auth.astro'
const validationError = Astro.url.searchParams.get('validation_error')const errorMessage = validationError ? "Please check your form inputs and try again." : undefined---
<Auth pageTitle="Create Event" errorMessage={errorMessage} errorType="error"> <form method="POST" action="/api/events/create"> <!-- Form fields --> </form></Auth>Pattern 3: Success Messages
Section titled “Pattern 3: Success Messages”---import Auth from '#layouts/Auth.astro'
const successParam = Astro.url.searchParams.get('success')const successMessage = successParam === 'saved' ? 'Your changes have been saved successfully.' : undefined---
<Auth pageTitle="Settings" errorMessage={successMessage} errorType="info"> <!-- Settings content --></Auth>Pattern 4: Multiple Error Conditions
Section titled “Pattern 4: Multiple Error Conditions”---import Auth from '#layouts/Auth.astro'
const saveError = Astro.url.searchParams.get('save_error')const deleteError = Astro.url.searchParams.get('delete_error')const networkError = Astro.url.searchParams.get('network_error')
const errorMessage = saveError ? "Failed to save. Please check your inputs." : deleteError ? "Cannot delete. Item is referenced by other records." : networkError ? "Network error. Please check your connection." : undefined---
<Auth pageTitle="User Management" errorMessage={errorMessage} errorType="error"> <!-- Content --></Auth>Props Reference
Section titled “Props Reference”errorMessage
Section titled “errorMessage”Type: string | undefined
Default: undefined
Description: Custom error message to display in alert
<!-- Automatic (no custom error) --><Auth pageTitle="Dashboard" />
<!-- Custom error --><Auth pageTitle="Settings" errorMessage="Failed to load settings"/>
<!-- Conditional error --><Auth pageTitle="Profile" errorMessage={hasError ? "An error occurred" : undefined}/>errorType
Section titled “errorType”Type: 'error' | 'warning' | 'info'
Default: 'error'
Description: Visual style of the alert
<!-- Error (red) --><Auth errorMessage="Access denied" errorType="error" />
<!-- Warning (orange) --><Auth errorMessage="Feature unavailable" errorType="warning" />
<!-- Info (blue) --><Auth errorMessage="Update successful" errorType="info" />Integration with API Endpoints
Section titled “Integration with API Endpoints”API endpoints can set error parameters for display on redirect:
import type { APIRoute } from 'astro'
export const POST: APIRoute = async ({ request, redirect }) => { try { const data = await request.json()
// Validation if (!isValid(data)) { return redirect('/dashboard/users?error=invalid_request') }
// Process update...
// Success return redirect('/dashboard/users?success=user_updated') } catch (error) { // Error return redirect('/dashboard/users?error=database_error') }}Extending Error Codes
Section titled “Extending Error Codes”To add new predefined error codes, update the ERROR_MESSAGES mapping in src/layouts/Auth.astro:
const ERROR_MESSAGES: Record<string, string> = { // Existing codes insufficient_permissions: 'You do not have permission to access that page.', session_expired: 'Your session has expired. Please sign in again.',
// Add new codes database_error: 'A database error occurred. Please try again later.', rate_limited: 'Too many requests. Please wait before trying again.', maintenance: 'System is under maintenance. Please check back later.',}Then use in redirects:
redirectUrl.searchParams.set('error', 'rate_limited')return Astro.redirect(redirectUrl.toString())Migration from Manual Error Handling
Section titled “Migration from Manual Error Handling”Before (Manual approach):
---import Auth from '#layouts/Auth.astro'import CardContainer from '#components/astro/CardContainer.astro'
// Manual error checkingconst errorParam = Astro.url.searchParams.get('error')const errorMessage = errorParam === 'insufficient_permissions' ? 'You do not have permission to access that page.' : null---
<Auth pageTitle="Dashboard"> {/* Manual error display */} {errorMessage && ( <section> <CardContainer> <div class="alert alert-error" role="alert"> <p><strong>Access Denied:</strong> {errorMessage}</p> </div> </CardContainer> </section> )}
<section> <!-- Dashboard content --> </section></Auth>After (Automatic approach):
---import Auth from '#layouts/Auth.astro'---
<Auth pageTitle="Dashboard"> <section> <!-- Dashboard content --> <!-- Error displays automatically above this section --> </section></Auth>Benefits:
- ✅ Removed ~15 lines of boilerplate code
- ✅ Consistent error display across all pages
- ✅ No manual error handling required
- ✅ DRY principle (Don’t Repeat Yourself)
Best Practices
Section titled “Best Practices”✅ Do: Trust Automatic Error Display
Section titled “✅ Do: Trust Automatic Error Display”<Auth pageTitle="Dashboard"> <!-- Errors display automatically --> <section>Dashboard content</section></Auth>❌ Don’t: Manually Handle Predefined Errors
Section titled “❌ Don’t: Manually Handle Predefined Errors”<!-- DON'T DO THIS -->---const errorParam = Astro.url.searchParams.get('error')const errorMessage = errorParam === 'insufficient_permissions' ? '...' : null---
<Auth pageTitle="Dashboard"> {errorMessage && <div class="alert">{errorMessage}</div>}</Auth>✅ Do: Use Descriptive Custom Messages
Section titled “✅ Do: Use Descriptive Custom Messages”<Auth errorMessage="Failed to save user profile. Please check required fields and try again." errorType="error">❌ Don’t: Use Generic Messages
Section titled “❌ Don’t: Use Generic Messages”<!-- DON'T DO THIS --><Auth errorMessage="Error" errorType="error">✅ Do: Choose Appropriate Alert Types
Section titled “✅ Do: Choose Appropriate Alert Types”<!-- Success message --><Auth errorMessage="Profile updated successfully" errorType="info" />
<!-- Non-critical issue --><Auth errorMessage="Some features temporarily unavailable" errorType="warning" />
<!-- Critical error --><Auth errorMessage="Access denied" errorType="error" />❌ Don’t: Misuse Alert Types
Section titled “❌ Don’t: Misuse Alert Types”<!-- DON'T DO THIS --><Auth errorMessage="Success!" errorType="error" />Secondary Navigation Slot
Section titled “Secondary Navigation Slot”The Auth layout provides a secondary-nav named slot that lets pages replace or suppress the default DashboardNavigation section.
How It Works
Section titled “How It Works”When secondary-nav is provided, it completely replaces the default nav section (including the <Nav> wrapper). If the slot is absent, the default DashboardNavigation renders unchanged.
// In Auth.astroconst hasSecondaryNav = Astro.slots.has('secondary-nav')
// Slot replaces default nav when presenthasSecondaryNav ? <slot name="secondary-nav" /> : <Nav><DashboardNavigation /></Nav>Usage Patterns
Section titled “Usage Patterns”Custom navigation with hidden items:
<Auth pageTitle="Dashboard"> <section slot="secondary-nav"> <DashboardNavigation hideItems={['orders']} /> </section>
<!-- page content --></Auth>Entirely custom navigation:
<Auth pageTitle="Settings"> <nav slot="secondary-nav"> <a href="/dashboard">Back to Dashboard</a> <a href="/settings/profile">Profile</a> </nav></Auth>Suppress navigation entirely:
<!-- Empty Fragment suppresses default nav --><Auth pageTitle="Focused Task"> <Fragment slot="secondary-nav" />
<!-- page content with no navigation rendered --></Auth>Real-World Example
Section titled “Real-World Example”The dashboard index page (src/pages/dashboard/index.astro) uses this slot to show all navigation items except Orders:
<Auth pageTitle="Dashboard"> <section slot="secondary-nav"> <DashboardNavigation hideItems={['orders']} /> </section>
<!-- dashboard content --></Auth>Troubleshooting
Section titled “Troubleshooting”Error Not Displaying
Section titled “Error Not Displaying”Problem: Error parameter in URL but no alert shown
Solutions:
- Verify Auth layout version supports error display (check for
errorMessageprop) - Check browser DevTools for redirect chain
- Inspect URL for error parameter
- Check for CSS hiding the alert
- Verify Auth layout wraps page content
Wrong Error Message
Section titled “Wrong Error Message”Problem: Shows raw error code instead of friendly message
Solution: Add error code to ERROR_MESSAGES mapping in Auth.astro
Custom Error Not Overriding
Section titled “Custom Error Not Overriding”Problem: URL param displays instead of custom prop
Solution: Ensure custom error is not undefined:
❌ <Auth errorMessage={undefined} /> <!-- Falls back to URL param -->✅ <Auth errorMessage="Custom error" /> <!-- Overrides URL param -->See Also
Section titled “See Also”- Auth Layout Role Guards - Role-based page protection
- Role Guard Usage - Component-level protection
- Configurable Roles - Role system configuration
Technical References
Section titled “Technical References”- Implementation:
src/layouts/Auth.astro- Props: Lines 24-33
- Error mapping: Lines 46-52
- Error resolution: Lines 54-58
- Alert display: Lines 122-143
- Technical Guide:
project-docs/02-guides/auth-layout-error-handling.md - Example: Auth layout role guards automatically use this system