# Error

*Display error states consistently with standardized messaging, optional details, and recovery options for better user experience.*

The `Error` [widget](../../01_Onboarding/02_Concepts/03_Widgets.md) provides a standardized way to display error states in your [app](../../01_Onboarding/02_Concepts/10_Apps.md). It's designed to communicate that something went wrong and optionally provide details and recovery options.

## Basic Usage

The simplest way to create an Error widget is by passing content directly to the constructor:

```csharp
public class BasicErrorView : ViewBase
{
    public override object? Build()
    {
        return new Error("Connection Failed", "Unable to connect to the server");
    }
}
```

> **tip:** Error widgets come with sensible defaults: no title, no message, and no stack trace. You can set these properties individually using the fluent extension methods.

### Title

Set a descriptive title for the error:

```csharp
public class ErrorTitleView : ViewBase
{
    public override object? Build()
    {
        return Layout.Vertical().Gap(4)
            | new Error().Title("Authentication Failed")
            | new Error().Title("Network Error")
            | new Error().Title("Validation Error");
    }
}
```

### Message

Provide a user-friendly error message:

```csharp
public class ErrorMessageView : ViewBase
{
    public override object? Build()
    {
        return Layout.Vertical().Gap(4)
            | new Error()
                .Title("Login Failed")
                .Message("Invalid username or password. Please try again.")
            | new Error()
                .Title("File Upload Error")
                .Message("The file size exceeds the maximum allowed limit of 10MB.")
            | new Error()
                .Title("Permission Denied")
                .Message("You don't have sufficient privileges to access this resource.");
    }
}
```

### Stack Trace

Include technical details for debugging (useful for developers):

```csharp
public class ErrorStackTraceView : ViewBase
{
    public override object? Build()
    {
        var stackTrace = @"at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at MyApp.Services.ApiService.GetDataAsync(String endpoint) in /src/Services/ApiService.cs:line 45
at MyApp.Views.DataView.LoadDataAsync() in /src/Views/DataView.cs:line 23";

        return new Error()
            .Title("API Connection Error")
            .Message("Failed to connect to the external service")
            .StackTrace(stackTrace);
    }
}
```

## Alternative Error Display Methods

While the `Error` widget is excellent for detailed error information, Ivy Framework provides several other ways to display errors depending on your needs:

### Error Callouts

Use [Callout.Error](12_Callout.md) for prominent error messages that need attention:

```csharp
public class ErrorCalloutExamplesView : ViewBase
{
    public override object? Build()
    {
        return Layout.Vertical().Gap(4)
            | Callout.Error("Failed to connect to the server. Please check your internet connection.")
            | Callout.Error("Invalid email format. Please enter a valid email address.", "Validation Error");
    }
}
```

### Error Toasts

Use `client.Toast` for non-intrusive error notifications:

```csharp
public class ClientErrorExamplesView : ViewBase
{
    public override object? Build()
    {
        var client = UseService<IClientProvider>();
        return new Button("Show System Error").Destructive()
            .HandleClick(_ => client.Error(new InvalidOperationException("System configuration validation failed")));
    }
}
```

### Text-Based Error Messages

Use [Text.Danger](01_TextBlock.md) for inline error text:

```csharp
public class TextErrorExamplesView : ViewBase
{
    public override object? Build()
    {
        return Text.Danger("Invalid email format");
    }
}
```

Display [validation errors](../../01_Onboarding/02_Concepts/08_Forms.md) using the `Invalid` property on [form inputs](../../01_Onboarding/02_Concepts/08_Forms.md):

```csharp
public class FormValidationErrorExamplesView : ViewBase
{
    public override object? Build()
    {
        var email = UseState("");
        var password = UseState("");
        var age = UseState(0);
        
        var emailError = UseState<string?>();
        var passwordError = UseState<string?>();
        var ageError = UseState<string?>();
        
        void ValidateForm()
        {
            // Clear previous errors
            emailError.Set((string?)null);
            passwordError.Set((string?)null);
            ageError.Set((string?)null);
            
            var hasErrors = false;
            
            if (string.IsNullOrWhiteSpace(email.Value)) {
                emailError.Set("Email is required");
                hasErrors = true;
            } else if (!email.Value.Contains("@")) {
                emailError.Set("Email must be a valid email address");
                hasErrors = true;
            }
            
            if (string.IsNullOrWhiteSpace(password.Value)) {
                passwordError.Set("Password is required");
                hasErrors = true;
            } else if (password.Value.Length < 8) {
                passwordError.Set("Password must be at least 8 characters long");
                hasErrors = true;
            }
            
            if (age.Value < 18) {
                ageError.Set("You must be at least 18 years old");
                hasErrors = true;
            }
            
            if (!hasErrors) {
                // Form is valid, proceed with submission
                // This would typically call an API or perform an action
            }
        }
        
        return Layout.Vertical().Gap(4)
            | Text.H3("Form Validation Errors")
            | Layout.Vertical().Gap(3)
                | Text.Label("Email")
                | email.ToTextInput()
                    .Placeholder("Enter your email")
                    .Invalid(emailError.Value)
                | Text.Label("Password")
                | password.ToPasswordInput()
                    .Placeholder("Enter your password")
                    .Invalid(passwordError.Value)
                | Text.Label("Age")
                | age.ToNumberInput()
                    .Placeholder("Enter your age")
                    .Invalid(ageError.Value)
            | new Button("Validate Form")
                .HandleClick(ValidateForm)
            | (emailError.Value != null || passwordError.Value != null || ageError.Value != null
                ? Callout.Error("Please fix the validation errors above", "Form Validation Failed")
                : null);
    }
}
```

### Exception Handling

Use the Error widget to display error states:

```csharp
public class ExceptionHandlingView : ViewBase
{
    public override object? Build()
    {
        var showError = UseState(false);
        var showDetails = UseState(false);
        
        void SimulateError()
        {
            showError.Set(true);
        }
        
        return Layout.Vertical().Gap(4)
            | new Button("Simulate Error").HandleClick(SimulateError).Destructive()
            | (showError.Value 
                ? Layout.Vertical().Gap(4)
                    | new Error()
                        .Title("Simulated Error")
                        .Message("This is a simulated error for demonstration purposes")
                        .StackTrace(showDetails.Value ? "at MyApp.Views.ErrorView.SimulateError() in /src/Views/ErrorView.cs:line 15" : null)
                    | new Button(showDetails.Value ? "Hide Details" : "Show Details")
                        .Variant(ButtonVariant.Outline)
                        .HandleClick(() => showDetails.Set(!showDetails.Value))
                : Text.Muted("Click the button above to simulate an error"));
    }
}
```

### Effect Error Handling

Demonstrate how effects can handle error states:

```csharp
public class EffectErrorView : ViewBase
{
    public override object? Build()
    {
        var showError = UseState(false);
        
        return Layout.Vertical().Gap(4)
            | new Button("Show Error")
                .HandleClick(_ => showError.Set(true))
            | (showError.Value 
                ? new Error()
                    .Title("Effect Failed")
                    .Message("The effect encountered an error during execution")
                : Text.Muted("Click button to show error"));
    }
}
```


## API

[View Source: Error.cs](https://github.com/Ivy-Interactive/Ivy-Framework/blob/main/src/Ivy/Widgets/Primitives/Error.cs)

### Constructors

| Signature |
|-----------|
| `new Error(string title = null, string message = null, string stackTrace = null)` |


### Properties

| Name | Type | Setters |
|------|------|---------|
| `Height` | `Size` | - |
| `Message` | `string` | `Message` |
| `Scale` | `Scale?` | - |
| `StackTrace` | `string` | `StackTrace` |
| `Title` | `string` | `Title` |
| `Visible` | `bool` | - |
| `Width` | `Size` | - |




## Examples


### Data Loading with Error Handling

Handle errors gracefully in data loading scenarios:

```csharp
public class DataLoadingView : ViewBase
{
    public override object? Build()
    {
        var isLoading = UseState(false);
        var hasError = UseState(false);
        var data = UseState<List<string>?>();
        
        async Task LoadData()
        {
            isLoading.Set(true);
            hasError.Set(false);
            
            // Simulate API call with random chance of failure
            await Task.Delay(1000);
            if (Random.Shared.Next(2) == 0)
            {
                hasError.Set(true);
            }
            else
            {
                data.Set(new List<string> { "Item 1", "Item 2", "Item 3" });
            }
            
            isLoading.Set(false);
        }
        
        // Initial load
        UseEffect(() => {
            _ = LoadData();
        }, []);
        
        return Layout.Vertical().Gap(4)
            | Layout.Horizontal().Gap(2)
                | new Button("Reload Data").HandleClick(async _ => await LoadData())
            | (isLoading.Value 
                ? "Loading..." 
                : hasError.Value 
                    ? new Error()
                        .Title("Failed to load data")
                        .Message("There was a problem connecting to the server")
                    : data.Value != null 
                        ? Layout.Vertical() | Text.H3("Data Items") | string.Join(", ", data.Value)
                        : null);
    }
}
```




### Error with Recovery Actions

Combine error display with actionable recovery options:

```csharp
public class ErrorRecoveryExamplesView : ViewBase
{
    public override object? Build()
    {
        var errorState = UseState<Exception?>();
        var recoveryStep = UseState(0);
        
        void SimulateRecoverableError()
        {
            errorState.Set(new InvalidOperationException("File system access denied. Insufficient permissions."));
            recoveryStep.Set(1);
        }
        
        void TryRecovery()
        {
            if (recoveryStep.Value < 3)
            {
                recoveryStep.Set(recoveryStep.Value + 1);
            }
            else
            {
                errorState.Set((Exception?)null);
                recoveryStep.Set(0);
            }
        }
        
        void SkipRecovery()
        {
            errorState.Set((Exception?)null);
            recoveryStep.Set(0);
        }
        
        return Layout.Vertical().Gap(4)
            | (Layout.Horizontal().Gap(2)
                | new Button("Simulate Error").Destructive()
                    .HandleClick(SimulateRecoverableError)
                | new Button("Try Recovery")
                    .HandleClick(TryRecovery)
                    .Disabled(errorState.Value == null)
                | new Button("Skip Recovery").Outline()
                    .HandleClick(SkipRecovery)
                    .Disabled(errorState.Value == null))
            | (errorState.Value != null 
                ? Layout.Vertical().Gap(3)
                    | new Error()
                        .Title("Recoverable Error")
                        .Message($"Step {recoveryStep.Value}/3: {errorState.Value.Message}")
                    | Callout.Info($"Recovery attempt {recoveryStep.Value} of 3. Click 'Try Recovery' to proceed.")
                    | (recoveryStep.Value >= 3 
                        ? Text.Success("Recovery completed successfully!")
                        : Text.Muted("Continue with recovery steps..."))
                : Text.Muted("Click 'Simulate Error' to start the recovery workflow"));
    }
}
```