How to Disable Exceptions in fmtlib: Complete Configuration Guide

Set the compile-time macro FMT_USE_EXCEPTIONS to 0 to disable C++ exceptions in fmtlib, which strips out all internal try/catch blocks and redirects error handling to fmt::assert_fail.

Disabling exceptions in {fmt} is critical for embedded systems, real-time applications, and environments compiled with -fno-exceptions. The library provides robust exception-free operation through the FMT_USE_EXCEPTIONS configuration macro, which is evaluated in include/fmt/core.h before any formatting logic is compiled.

Understanding the FMT_USE_EXCEPTIONS Macro

The {fmt} library controls exception support through the FMT_USE_EXCEPTIONS macro defined in include/fmt/core.h (lines 46–57). When this macro evaluates to 0, the library eliminates exception overhead by redefining exception handling constructs as no-ops.

// include/fmt/core.h – exception control macros (lines 46-57)
#if FMT_USE_EXCEPTIONS

#  define FMT_TRY   try

#  define FMT_CATCH(x) catch (x)

#else

#  define FMT_TRY   if (true)          // no try block generated

#  define FMT_CATCH(x) if (false)     // no catch block generated

#endif

When FMT_USE_EXCEPTIONS is 0, the library automatically translates all throw fmt::format_error statements into calls to fmt::assert_fail, which aborts the program by default. The macro is automatically detected if you compile with -fno-exceptions on GCC/Clang or with _HAS_EXCEPTIONS==0 on MSVC, but you can also override it manually.

Methods to Disable Exceptions in fmtlib

You can disable exceptions through three primary configuration methods, depending on your build system and integration approach.

CMake Configuration

When building {fmt} as a compiled library, pass the CMake option to disable exception handling at the configuration stage:

cmake -DFMT_USE_EXCEPTIONS=OFF ..

# or explicitly set to 0

cmake -DFMT_USE_EXCEPTIONS=0 ..

This definition propagates through the build system defined in CMakeLists.txt and sets the preprocessor macro consistently across all translation units.

Compiler Flags

Define the macro via compiler flags when building your project. This method works for both header-only and compiled library usage:


# GCC/Clang

g++ -std=c++20 -DFMT_USE_EXCEPTIONS=0 -I/path/to/fmt/include main.cpp -lfmt

# MSVC

cl /std:c++20 /DFMT_USE_EXCEPTIONS=0 /I\path\to\fmt\include main.cpp fmt.lib

Source-Level Macro Definition

Define FMT_USE_EXCEPTIONS before including any {fmt} headers. This approach is necessary when using header-only mode (FMT_HEADER_ONLY):

#define FMT_USE_EXCEPTIONS 0          // Must precede all fmt headers
#include <fmt/core.h>
#include <fmt/format.h>

int main() {
    // Format errors now trigger assert_fail instead of throwing
    fmt::print("Value: {}\n", 42);
}

According to the official documentation in doc/api.md (lines 87–89), the default value is 1 (exceptions enabled), or 0 when the compiler disables exceptions.

Error Handling Without Exceptions

When exceptions are disabled, {fmt} replaces exception-based error reporting with an assertion mechanism that offers deterministic termination and optional customization.

The assert_fail Mechanism

By default, fmt::assert_fail writes an error message to stderr and calls std::abort(). The function signature matches the standard assertion pattern:

void fmt::assert_fail(const char* msg, const char* file, int line);

Custom Assertion Handlers

For projects requiring custom error recovery (such as logging errors or returning error codes), define FMT_CUSTOM_ASSERT_FAIL before including headers and provide your own implementation:

#define FMT_USE_EXCEPTIONS 0
#define FMT_CUSTOM_ASSERT_FAIL 1
#include <fmt/core.h>
#include <iostream>

void fmt::assert_fail(const char* msg, const char* file, int line) {
    std::cerr << "Format error at " << file << ":" << line 
              << " - " << msg << std::endl;
    // Custom handling: log, set error flag, or throw different type
    std::terminate();  // Required: must not return
}

Practical Code Examples

Triggering error handling without exceptions:

#define FMT_USE_EXCEPTIONS 0
#include <fmt/format.h>
#include <iostream>

int main() {
    // This valid call works normally
    auto s = fmt::format("Hello, {}!", "world");
    
    // This malformed format string triggers fmt::assert_fail
    // instead of throwing fmt::format_error
    fmt::format("{:d}", "not-a-number");  // Aborts or calls custom handler
}

Complete build command for exception-free static library:


# Configure and build fmt without exceptions

git clone https://github.com/fmtlib/fmt.git
cd fmt
cmake -B build -DFMT_USE_EXCEPTIONS=OFF -DFMT_DOC=OFF -DFMT_TEST=OFF
cmake --build build --config Release

Summary

  • Macro control: Use FMT_USE_EXCEPTIONS defined in include/fmt/core.h to toggle exception support at compile time.
  • Automatic detection: {fmt} automatically sets FMT_USE_EXCEPTIONS=0 when compiled with -fno-exceptions or _HAS_EXCEPTIONS==0.
  • Three configuration methods: CMake option (-DFMT_USE_EXCEPTIONS=OFF), compiler flag (-DFMT_USE_EXCEPTIONS=0), or source-level #define.
  • Error redirection: Disabled exceptions route errors to fmt::assert_fail, which can be customized via FMT_CUSTOM_ASSERT_FAIL for project-specific error handling.
  • Header-only compatibility: Exception disabling works identically in FMT_HEADER_ONLY mode.

Frequently Asked Questions

What happens when FMT_USE_EXCEPTIONS is set to 0?

All internal TRY/CATCH macros expand to no-ops, and any formatting error that would normally throw fmt::format_error instead calls fmt::assert_fail. The program aborts unless you provide a custom handler via FMT_CUSTOM_ASSERT_FAIL.

Can I use fmtlib without exceptions in header-only mode?

Yes. Define FMT_USE_EXCEPTIONS 0 before including any {fmt} headers when using FMT_HEADER_ONLY. The macro controls conditional compilation in include/fmt/core.h regardless of whether you link against the compiled library or include headers directly.

How do I handle errors gracefully when exceptions are disabled?

Implement a custom fmt::assert_fail function and define FMT_CUSTOM_ASSERT_FAIL before including headers. Your implementation can log errors to external systems, set global error flags, or invoke alternative exception types, but it must not return (typically ending with std::terminate() or std::abort()).

Does disabling exceptions improve performance?

Disabling exceptions eliminates the overhead of exception handling tables (EH tables) and stack unwinding information, which can reduce binary size and improve cache locality. However, error handling becomes fatal by default, so you should only disable exceptions if your application can tolerate termination on format errors or if you implement FMT_CUSTOM_ASSERT_FAIL to handle errors appropriately.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →