# spdlog Error Handling: How to Implement Custom Error Handlers in C++

> Discover spdlog's error handling and learn to implement custom C++ error handlers. Configure global or logger-specific handlers to manage logging exceptions effectively.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: how-to-guide
- Published: 2026-07-17

---

**spdlog catches internal logging exceptions and forwards error messages to a customizable handler function that users can configure globally via `spdlog::set_error_handler()` or per-logger via `logger::set_error_handler()` to replace the default stderr output.**

The spdlog C++ logging library protects application stability by isolating logging failures through a centralized **spdlog error handling** system. When sinks fail or formatting throws, the library catches exceptions and routes them to a user-configurable callback instead of crashing. This mechanism is managed through the `spdlog::details::registry` class and individual logger instances, giving you granular control over failure recovery strategies.

## How spdlog Error Handling Works

spdlog wraps every logging operation in a try-catch block inside the `logger::log()` method. When an exception occurs—such as a disk-full error during file sink output or a formatting exception—the library constructs an error message string and invokes the configured handler.

The system supports two handler scopes:

- **Global handler**: Set via `spdlog::set_error_handler()` in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) (lines 90-92), stored in the registry, and automatically applied to all new loggers.
- **Per-logger handler**: Set via `logger::set_error_handler()` declared in [`include/spdlog/logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger.h) (lines 310-311), allowing specific loggers to override the global behavior.

Both handlers must match the signature `void handler(const std::string &msg);`. The default implementation simply writes the message to `stderr`, allowing the application to continue running.

## Registry Architecture and Source Locations

The error handling infrastructure resides in the registry pattern implementation. When you call `spdlog::set_error_handler()`, the inline implementation in [`include/spdlog/spdlog-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog-inl.h) (lines 54-56) forwards the call to `spdlog::details::registry`.

Key source file responsibilities:

- [`include/spdlog/details/registry.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry.h) (lines 79-82): Declares the global handler storage interface.
- [`include/spdlog/details/registry-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry-inl.h) (lines 165-168): Implements handler propagation to newly created loggers.
- [`include/spdlog/logger-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger-inl.h) (lines 112-114): Defines the per-logger `set_error_handler` storage mechanism.
- [`tests/test_errors.cpp`](https://github.com/gabime/spdlog/blob/main/tests/test_errors.cpp): Contains unit tests demonstrating handler customization.

## Setting a Global Error Handler

To intercept all spdlog internal errors application-wide, register a callback function before creating loggers. This is ideal for production services that need to redirect errors to monitoring systems or crash dumps.

```cpp
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <cstdlib>

int main() {
    // Set global handler in include/spdlog/spdlog.h
    spdlog::set_error_handler([](const std::string &msg) {
        // Custom error processing
        auto err_sink = spdlog::stderr_color_mt("internal_errors");
        err_sink->critical("Logging system failure: {}", msg);
        
        // Optionally abort on critical logging failures
        std::abort();
    });

    // All subsequent loggers inherit this handler
    auto app_logger = spdlog::stdout_color_mt("app");
    app_logger->info("Application started");
}

```

The registry automatically applies this handler to every logger created after the call, as implemented in [`include/spdlog/details/registry-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry-inl.h).

## Setting a Per-Logger Error Handler

For library code or specific subsystems that require distinct error policies, override the handler on individual logger instances. This stores the callable directly in the logger object's internal state.

```cpp
auto file_logger = spdlog::basic_logger_mt("file", "app.log");

// Define custom exception type
struct logging_error : std::runtime_error {
    using std::runtime_error::runtime_error;
};

// Override handler specific to this logger (include/spdlog/logger.h)
file_logger->set_error_handler([](const std::string &msg) {
    throw logging_error("File sink failure: " + msg);
});

try {
    file_logger->info("Writing to potentially full disk");
} catch (const logging_error &e) {
    // Handle logging failure in application-specific way
    std::cerr << "Recoverable logging error: " << e.what() << std::endl;
}

```

## Handler Precedence and Interaction

When both handlers are configured, **per-logger handlers take precedence** over the global handler. If a logger has its own error handler set via `logger::set_error_handler()`, the registry's global handler is bypassed for that instance. This allows you to maintain a default stderr policy for most loggers while implementing custom recovery logic for critical paths.

## Production Error Handling Strategies

Choose your handler implementation based on deployment context.

**Abort on failure** for critical infrastructure where logging must succeed:

```cpp
spdlog::set_error_handler([](const std::string &) {
    std::abort();
});

```

**Alternative sink redirection** for microservices that need clean log separation:

Redirect to syslog or dedicated error files to avoid interleaving with stdout logs, particularly important in multi-process environments.

**Exception propagation** for library development:

Use per-logger handlers to throw custom exceptions that library consumers can catch, converting silent logging failures into actionable errors that surface in user code.

## Summary

- **spdlog error handling** uses a callback mechanism with the signature `void handler(const std::string &msg)` to process internal logging failures.
- Configure global handlers via `spdlog::set_error_handler()` in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) for application-wide policies.
- Configure per-logger handlers via `logger::set_error_handler()` in [`include/spdlog/logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger.h) for specific error recovery strategies.
- The `spdlog::details::registry` class manages handler storage and automatically propagates global settings to new loggers.
- Per-logger handlers override global handlers, allowing granular control over error response behaviors.

## Frequently Asked Questions

### What is the default spdlog error handler?

The default handler writes error messages to `stderr` using standard output streams and allows the application to continue executing. This prevents logging failures from crashing the application while still making errors visible during development. You can replace this default at any time by calling `spdlog::set_error_handler()` with your own callable.

### Can I throw exceptions from within a custom error handler?

Yes, you can throw exceptions from custom handlers, but be aware that the exception will propagate from the logging call site. If you throw from a global handler, any logging operation that triggers an internal error will throw, potentially affecting all logging throughout your application. For targeted exception handling, use per-logger handlers instead.

### How do I reset the error handler to the default behavior?

Pass an empty callable or re-implement the default behavior to `spdlog::set_error_handler()`. However, spdlog does not provide a direct "reset to default" function, so you must capture the original default behavior yourself before overriding it, or simply set a new handler that writes to `stderr` and continues execution.

### Does spdlog error handling affect application performance?

The error handling mechanism only incurs overhead when an actual error occurs, as it operates within catch blocks. The normal logging hot path does not check error handler state, so there is no runtime performance penalty for having custom handlers configured during successful logging operations.