How to Handle Exceptions with fmtlib: A Complete Guide to format_error and FMT_THROW
fmtlib uses fmt::format_error—a std::runtime_error subclass—thrown via the FMT_THROW macro, with built-in support for compiling without exceptions.
The {fmt} library (commonly known as fmtlib) provides a minimal, predictable exception hierarchy for reporting formatting failures. Understanding how to catch, customize, or disable these exceptions is essential for robust error handling in C++ applications. This guide covers the complete exception-handling mechanism as implemented in fmtlib/fmt.
The fmt::format_error Exception Type
All formatting errors in fmtlib raise fmt::format_error, defined in [include/fmt/format.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) at lines 1112–1115:
class format_error : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
};
This single exception type handles every error condition—malformed format strings, type mismatches, compilation failures, and system-level I/O problems. Because it inherits from std::runtime_error, you can catch it specifically or handle it generically through std::exception.
The FMT_THROW Macro: How Exceptions Are Raised
fmtlib abstracts all throw operations through the FMT_THROW macro, defined in [include/fmt/format.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) at lines 162–168:
#ifdef FMT_THROW
// use user-provided definition
#elif FMT_USE_EXCEPTIONS
#define FMT_THROW(x) throw x
#else
#define FMT_THROW(x) ::fmt::assert_fail(__FILE__, __LINE__, (x).what())
#endif
The macro provides three behaviors:
- User override: Define
FMT_THROWbefore including fmt headers to inject custom error handling - Standard mode (default): When
FMT_USE_EXCEPTIONSis defined, expands to normalthrow - Exception-free mode: Calls
fmt::assert_fail, which prints diagnostics and aborts the program
This design allows the same source code to compile with or without exception support.
Where fmtlib Throws Exceptions
Formatting errors originate from several core headers:
- [
include/fmt/format.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) – Malformed format strings such as missing closing braces throwFMT_THROW(format_error("unmatched '{' in format string"))at line 390 - [
include/fmt/compile.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/compile.h) – Compile-time format validation failures - [
include/fmt/chrono.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h) – Date/time parsing and formatting errors - [
include/fmt/xchar.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/xchar.h) – System-level failures such asFMT_THROW(system_error(errno, FMT_STRING("cannot write to file")))at line 316 - [
include/fmt/format-inl.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/format-inl.h) – Runtime errors including memory allocation failures
Catching fmtlib Exceptions
Catch fmt::format_error specifically for targeted handling, or use std::exception for broad coverage:
#include <fmt/core.h>
#include <iostream>
int main() {
try {
// Malformed format string: missing '}'
fmt::print("Hello {0!\n", 42);
} catch (const fmt::format_error& e) {
// Specific fmt exception handling
std::cerr << "fmt error: " << e.what() << '\n';
} catch (const std::exception& e) {
// Generic fallback
std::cerr << "standard error: " << e.what() << '\n';
}
}
The what() message originates from the string passed to format_error's constructor, providing actionable diagnostics.
Compiling fmtlib Without Exceptions
For projects that disable C++ exceptions, define FMT_USE_EXCEPTIONS=0 before including fmt headers or pass it to your compiler:
#define FMT_USE_EXCEPTIONS 0
#include <fmt/core.h>
int main() {
// Formatting errors now trigger abort via fmt::assert_fail
fmt::print("Bad { format\n");
}
With exceptions disabled:
FMT_THROWexpands tofmt::assert_fail(__FILE__, __LINE__, message)- The program prints the file, line, and error message, then terminates
- Behavior matches standard assertion failures—no stack unwinding occurs
Customizing Error Handling with FMT_THROW
Override the FMT_THROW macro to redirect errors without modifying fmtlib source:
#include <iostream>
#define FMT_THROW(e) (std::cerr << "Custom handler: " << (e).what() << '\n', throw e)
#include <fmt/core.h>
int main() {
try {
fmt::print("{:invalid}\n", 42);
} catch (const std::exception& e) {
// Handler executes before throw
}
}
Place this definition before any fmt include to intercept all error sites across [format.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h), [compile.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/compile.h), [chrono.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), and [xchar.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/xchar.h).
Summary
- Single exception type:
fmt::format_errorinherits fromstd::runtime_errorand handles all formatting errors - Macro abstraction:
FMT_THROWcontrols whether to throw, abort, or call custom handlers - Exception-free builds: Define
FMT_USE_EXCEPTIONS=0to replace throws withfmt::assert_fail - Flexible catching: Target
fmt::format_errorspecifically or catch throughstd::exception - Customization hook: Pre-define
FMT_THROWto inject project-specific error handling
Frequently Asked Questions
What exception does fmtlib throw for invalid format strings?
fmtlib throws fmt::format_error for all format string errors. This type is defined in [include/fmt/format.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) at lines 1112–1115 and inherits from std::runtime_error. The exception includes a descriptive message accessible via what().
Can I use fmtlib in a project compiled without C++ exceptions?
Yes. Define FMT_USE_EXCEPTIONS=0 before including fmt headers. In this mode, FMT_THROW expands to fmt::assert_fail, which prints the error location and message, then aborts. The same source code works in both configurations without modification.
How do I catch fmtlib errors in a generic exception handler?
Catch const std::exception& or const std::runtime_error&, since fmt::format_error inherits from both. For targeted handling, catch const fmt::format_error& specifically. The library throws no other custom exception types, keeping the surface area minimal.
Is there a way to customize fmtlib's error handling without modifying the library?
Yes. Pre-define the FMT_THROW macro with your own implementation before including any fmt headers. Your macro receives the exception object as its argument and can log, transform, or rethrow as needed. This affects all error sites including [format.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h), [xchar.h](https://github.com/fmtlib/fmt/blob/main/include/fmt/xchar.h), and other headers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →