# Debugging and Error Reporting Architecture in Fastfetch: A Technical Deep Dive

> Explore the fastfetch debugging and error reporting architecture. Learn how FF_DEBUG and ffPrintError() handle compile-time and runtime messages using configurable flags.

- Repository: [fastfetch-cli/fastfetch](https://github.com/fastfetch-cli/fastfetch)
- Tags: architecture
- Published: 2026-03-30

---

**Fastfetch employs a dual-layer architecture where the `FF_DEBUG` macro handles compile-time conditional logging to `stderr`, while `ffPrintError()` manages runtime user-facing error messages, both governed by flags stored in `instance.config.display` that respond to command-line arguments and environment variables.**

Fastfetch is a high-performance system information tool written in C that must balance detailed diagnostic capabilities for developers with clean, error-free output for end users. The **fastfetch-cli/fastfetch** repository implements a cohesive **debugging and error reporting architecture** through a centralized configuration system that separates internal instrumentation from user-facing failure messages, allowing granular control via compile-time definitions, runtime flags, and environment variables.

## Core Debugging Infrastructure

The debugging system centers on a compile-time macro that evaluates runtime configuration flags before emitting any output.

### The FF_DEBUG Macro

In [`src/common/debug.h`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/debug.h), the `FF_DEBUG(...)` macro expands to a conditional `fprintf(stderr, …)` statement. This expansion only occurs when the program is compiled **without** the `NDEBUG` definition, ensuring zero overhead in release builds. At runtime, the macro checks `instance.config.display.debugMode` before printing any diagnostic information.

This design allows developers to instrument detection logic throughout the codebase without affecting production performance. When enabled, debug output includes file paths, function names, and internal state variables that help trace execution flow through the various detection modules.

### Debug Flag Configuration

The `debugMode` boolean resides in the `FFOptionsDisplay` structure and is parsed in [`src/options/display.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/options/display.c). Users can activate debugging through two mechanisms:

- **Command-line option**: `--debug` invokes `ffOptionParseBoolean` to set the flag directly
- **Environment variable**: In non-release builds, the code evaluates `options->debugMode = !!getenv("FF_DEBUG")` during initialization, allowing developers to enable debugging without modifying command-line arguments

Both methods update the global `instance` configuration created by `ffMain()` in [`src/fastfetch.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/fastfetch.c), making the debug state available to all subsequent detection operations.

## Centralized Error Reporting

While debugging serves developers, error reporting addresses user visibility into detection failures without cluttering standard output.

### The ffPrintError Function

The function `ffPrintError()` in [`src/common/impl/printing.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/printing.c) provides the primary interface for reporting detection failures. Unlike debug output which goes to `stderr`, error messages flow through the same formatting pipeline as regular module output, respecting pipe mode, color settings, and logo positioning.

The function accepts a module name constant (such as `FF_WIFI_MODULE_NAME`), an error code, formatting options, and a message string. Before emitting any text, it verifies that `instance.config.display.showErrors` is enabled, ensuring that normal users see clean output unless they explicitly request error details.

### Error Display Configuration

The `showErrors` flag is defined in [`src/options/display.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/options/display.c) alongside `debugMode`, but controlled through separate user-facing options:

- **`--show-errors`**: Toggles the boolean flag directly via `ffOptionParseBoolean`
- **`--stat`**: Implicitly enables error reporting while also printing module exit status codes

By default, `showErrors` is `false`, meaning detection failures fail silently in standard operation. This default behavior prioritizes aesthetic output over diagnostic verbosity for typical use cases.

## Module Integration Patterns

Detection modules interact with both systems at different phases of execution, creating a consistent debugging experience across the entire detection stack.

### Detection Module Usage

Modules throughout `src/detection/` implement a standard pattern for error and debug handling. For example, in [`src/detection/wifi/wifi_linux.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/wifi/wifi_linux.c), the code first logs its entry point:

```c
FF_DEBUG("Starting NetworkManager wifi detection for interface %s", iface->name);

```

If the detection routine fails, it returns an error string that the caller passes to `ffPrintError()`:

```c
const char *err = ffDetectWifi(&result);
if (err) {
    ffPrintError(FF_WIFI_MODULE_NAME, 0, &options->moduleArgs,
                 FF_PRINT_TYPE_DEFAULT, "%s", err);
    return false;
}

```

This pattern appears consistently across platform-specific detection files, ensuring that developers can trace execution paths while users receive contextual error information only when requested.

### Low-Level I/O Diagnostics

Utility functions in [`src/common/impl/io_unix.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/io_unix.c) and [`src/common/impl/io_windows.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/io_windows.c) provide additional granularity by checking `instance.config.display.debugMode` directly before emitting diagnostics. When debugging is active, these helpers log file-open failures, read errors, and path resolution issues that would otherwise be invisible to higher-level detection logic.

For example, a Unix I/O helper might include:

```c
if (instance.config.display.debugMode) {
    FF_DEBUG("Failed to read %s: %s", path, strerror(errno));
}

```

This approach captures system-level failures at the source while maintaining the conditional compilation protections of the `FF_DEBUG` macro.

## Runtime Configuration Flow

The architecture initializes through a specific sequence that establishes the debugging context before any detection occurs. In [`src/fastfetch.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/fastfetch.c), the `ffMain()` function creates the global `instance` structure and populates `instance.config.display` by parsing command-line arguments via the options modules.

During this startup phase, the code evaluates both compile-time definitions (`NDEBUG`) and runtime inputs (`--debug`, `FF_DEBUG`, `--show-errors`). Once initialized, the configuration remains immutable for the program's duration, ensuring consistent behavior across all detection modules.

The separation between compile-time macro expansion and runtime flag evaluation creates a tiered system: developers get maximum verbosity during builds with debugging symbols, while production binaries maintain optimal performance with the option for users to surface errors when troubleshooting specific hardware detection issues.

## Summary

- **Fastfetch** implements debugging through the `FF_DEBUG` macro in [`src/common/debug.h`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/debug.h), which compiles to nothing in release builds but logs to `stderr` in development when `instance.config.display.debugMode` is true.
- **Error reporting** uses `ffPrintError()` in [`src/common/impl/printing.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/printing.c), which respects the `showErrors` flag and formats messages through the standard output pipeline.
- **Configuration** is centralized in [`src/options/display.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/options/display.c), supporting both `--debug`/`FF_DEBUG` for diagnostics and `--show-errors`/`--stat` for error visibility.
- **Module integration** follows a consistent pattern where detection routines call `FF_DEBUG()` for tracing and `ffPrintError()` for failure reporting, as seen in [`src/detection/wifi/wifi_linux.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/wifi/wifi_linux.c).
- **I/O helpers** in [`src/common/impl/io_unix.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/io_unix.c) and [`io_windows.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/io_windows.c) check debug flags directly to log low-level system call failures.

## Frequently Asked Questions

### How do I enable debug logging in fastfetch?

Set the environment variable `FF_DEBUG=1` and ensure you are running a build compiled without `NDEBUG`, or pass the `--debug` flag on the command line. Both methods set `instance.config.display.debugMode` to true, causing `FF_DEBUG()` macros to emit diagnostic information to standard error.

### What is the difference between `--debug` and `--show-errors` in fastfetch?

The `--debug` flag activates developer-focused diagnostic output via the `FF_DEBUG` macro, showing internal state and execution paths. The `--show-errors` flag enables user-facing error messages through `ffPrintError()`, displaying detection failures in the formatted output without exposing internal debugging details. The `--stat` option enables error reporting while also showing exit status codes.

### Where does fastfetch handle the parsing of debug and error flags?

Command-line parsing occurs in [`src/options/display.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/options/display.c), where `ffOptionParseBoolean` processes `--debug` and `--show-errors`. The code also checks for the `FF_DEBUG` environment variable in non-release builds. These values populate the `FFOptionsDisplay` structure within the global `instance` created in [`src/fastfetch.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/fastfetch.c).

### Why do some fastfetch builds show no debug output even with `--debug`?

Release builds define `NDEBUG` during compilation, which causes the `FF_DEBUG` macro to expand to nothing, eliminating all debug logging code regardless of runtime flags. To see debug output, you must compile from source without the `NDEBUG` definition, typically by using a debug or development build configuration.