Blazor Built-in Components Created: 04 Feb 2026 Updated: 04 Feb 2026

ErrorBoundary Component in ASP.NET Core Blazor

The ErrorBoundary component, introduced in .NET 6, provides a convenient way to handle exceptions in Blazor components. Instead of letting the entire page crash when an error occurs, you can wrap components with ErrorBoundary to gracefully handle errors and display a friendly error message.

Why Use ErrorBoundary?

Without ErrorBoundaryWith ErrorBoundary
❌ Entire page crashes✅ Only affected component shows error
❌ Poor user experience✅ Graceful error handling
❌ User must refresh page✅ Can recover without refresh
❌ No error context✅ Access to exception details

Basic Usage

Wrap any component with ErrorBoundary to catch exceptions:

@page "/my-page"
@rendermode InteractiveServer

<ErrorBoundary>
<MyComponent />
</ErrorBoundary>

When MyComponent throws an exception, Blazor displays a default error UI instead of crashing the page.

Custom Error Content

Provide a custom error message using ChildContent and ErrorContent:

<ErrorBoundary>
<ChildContent>
<MyComponent />
</ChildContent>
<ErrorContent>
<div class="alert alert-danger">
<h5>Something went wrong!</h5>
<p>An error occurred. Please try again later.</p>
</div>
</ErrorContent>
</ErrorBoundary>

Accessing Exception Details

Use the Context parameter to access the caught exception:

<ErrorBoundary>
<ChildContent>
<MyComponent />
</ChildContent>
<ErrorContent Context="exception">
<div class="alert alert-danger">
<h5>Error Details</h5>
<p><strong>Type:</strong> @exception.GetType().Name</p>
<p><strong>Message:</strong> @exception.Message</p>
</div>
</ErrorContent>
</ErrorBoundary>
Security Note: In production, avoid showing detailed exception messages to users. Log them server-side instead.

Recovering from Errors

Use the Recover() method to reset the error state and re-render the component:

<ErrorBoundary @ref="errorBoundary">
<ChildContent>
<MyComponent />
</ChildContent>
<ErrorContent Context="ex">
<div class="alert alert-warning">
<p>Error: @ex.Message</p>
<button class="btn btn-primary" @onclick="HandleRecover">
Try Again
</button>
</div>
</ErrorContent>
</ErrorBoundary>

@code {
private ErrorBoundary? errorBoundary;

private void HandleRecover()
{
errorBoundary?.Recover();
}
}

What Recover() Does

  1. Clears the error state
  2. Re-renders the ChildContent
  3. Resets the wrapped component to its initial state

Nested ErrorBoundaries

Wrap individual components to isolate failures:

<div class="row">
<div class="col-md-4">
<ErrorBoundary>
<ChildContent>
<WidgetA />
</ChildContent>
<ErrorContent>
<div class="alert alert-danger">Widget A failed</div>
</ErrorContent>
</ErrorBoundary>
</div>
<div class="col-md-4">
<ErrorBoundary>
<ChildContent>
<WidgetB />
</ChildContent>
<ErrorContent>
<div class="alert alert-danger">Widget B failed</div>
</ErrorContent>
</ErrorBoundary>
</div>
<div class="col-md-4">
<ErrorBoundary>
<ChildContent>
<WidgetC />
</ChildContent>
<ErrorContent>
<div class="alert alert-danger">Widget C failed</div>
</ErrorContent>
</ErrorBoundary>
</div>
</div>

Result: If Widget B throws an exception, only Widget B shows an error. Widget A and Widget C continue working normally.

ErrorBoundary in Layouts

Wrap the entire page content in a layout to catch any unhandled exceptions:

@inherits LayoutComponentBase

<div class="page">
<Sidebar />
<main>
<ErrorBoundary @ref="errorBoundary">
<ChildContent>
@Body
</ChildContent>
<ErrorContent Context="ex">
<div class="container mt-5">
<div class="alert alert-danger">
<h4>An error occurred</h4>
<p>We're sorry, but something went wrong.</p>
<button class="btn btn-primary" @onclick="Recover">
Return to Home
</button>
</div>
</div>
</ErrorContent>
</ErrorBoundary>
</main>
</div>

@code {
private ErrorBoundary? errorBoundary;

private void Recover()
{
errorBoundary?.Recover();
NavigationManager.NavigateTo("/");
}
}

Complete Example

BuggyCounter.razor (Component that throws)

<div class="border rounded p-3">
<h6>@Title</h6>
<p>Current count: @currentCount</p>
<button class="btn btn-danger" @onclick="IncrementCount">
Click me (Throws at 3)
</button>
</div>

@code {
[Parameter]
public string Title { get; set; } = "Buggy Counter";

private int currentCount = 0;

private void IncrementCount()
{
currentCount++;

if (currentCount >= 3)
{
throw new InvalidOperationException(
$"Counter reached {currentCount}! This is a simulated error.");
}
}
}

ErrorBoundaryDemo.razor (Page using ErrorBoundary)

@page "/error-boundary-demo"
@rendermode InteractiveServer

<h1>ErrorBoundary Demo</h1>

<ErrorBoundary @ref="errorBoundary">
<ChildContent>
<BuggyCounter />
</ChildContent>
<ErrorContent Context="exception">
<div class="alert alert-danger">
<h5>Oops! Something went wrong</h5>
<p><strong>Error:</strong> @exception.Message</p>
<button class="btn btn-primary" @onclick="HandleRecover">
Try Again
</button>
</div>
</ErrorContent>
</ErrorBoundary>

@code {
private ErrorBoundary? errorBoundary;

private void HandleRecover()
{
errorBoundary?.Recover();
}
}

ErrorBoundary with Logging

Log errors for monitoring while showing a friendly message to users:

@inject ILogger<MyPage> Logger

<ErrorBoundary @ref="errorBoundary">
<ChildContent>
<MyComponent />
</ChildContent>
<ErrorContent Context="ex">
@{
LogError(ex);
}
<div class="alert alert-danger">
<p>An unexpected error occurred. Our team has been notified.</p>
<button class="btn btn-primary" @onclick="Recover">Try Again</button>
</div>
</ErrorContent>
</ErrorBoundary>

@code {
private ErrorBoundary? errorBoundary;

private void LogError(Exception ex)
{
Logger.LogError(ex, "Error in MyComponent: {Message}", ex.Message);
}

private void Recover()
{
errorBoundary?.Recover();
}
}

Default Error UI Styling

When no ErrorContent is provided, Blazor shows a default error UI. Customize it with CSS:

/* In your app.css */
.blazor-error-boundary {
background: #ffcccc;
padding: 1rem;
border: 1px solid #ff0000;
border-radius: 4px;
}

.blazor-error-boundary::after {
content: "An error occurred. Please try again.";
color: #cc0000;
font-weight: bold;
}

Limitations

LimitationDescription
Render-time onlyOnly catches errors during rendering, not in event handlers by default
No async lifecycleDoesn't catch errors in OnInitializedAsync after first render
Client-side onlyFor Blazor WebAssembly, server errors need separate handling

Handling Event Handler Errors

For errors in event handlers, wrap the code in try-catch:

@code {
private async Task HandleClick()
{
try
{
await SomeRiskyOperationAsync();
}
catch (Exception ex)
{
// Handle or log the error
errorMessage = ex.Message;
}
}
}

Best Practices

  1. Wrap critical components - Don't wrap everything; focus on components that may fail
  2. Provide recovery options - Give users a way to retry or navigate away
  3. Log errors server-side - Don't expose stack traces to users
  4. Use nested boundaries - Isolate failures to minimize impact
  5. Test error scenarios - Verify your error handling works as expected

Summary

FeatureDescription
<ErrorBoundary>Wraps components to catch exceptions
<ChildContent>The protected component(s)
<ErrorContent>Custom UI shown on error
Context="ex"Access the caught exception
@ref + Recover()Reset error state and re-render


Share this lesson: