---
name: "exterror"
section: "9"
platform: "freebsd"
package: "base"
version: "16.0-CURRENT-20261027-61c70dc16a79"
release: "FreeBSD 16.0-CURRENT (2026-10-27)"
platforms: ["freebsd"]
url: "https://new.carta.tech/exterror"
---

# exterror(9)

provide extended error information to userspace

## NAME

**exterror** – provide extended error information to userspace

## SYNOPSIS

```
#define EXTERR_CATEGORY_DYNAMIC "path/to/this/file.c"
#define	EXTERR_CATEGORY EXTERR_CAT_MYCATEGORY
```

**#include \<sys/exterrvar.h\>**

*struct* *kexterr;*

*void*\

**exterr\_clear**(*struct kexterr \*ke*);

*int*\

**exterr\_set\_from**(*const struct kexterr \*ke*);

*int*\

**EXTERROR**(*int error*, *const char \*msg*, *...*);

*void*\

**EXTERROR\_KE**(*struct kexterr \*ke*, *int error*, *const char \*msg*, *...*);

## DESCRIPTION

The **exterror** framework allows the kernel to return additional information about an error along with the standard [errno(3)](/errno/3.md) error code, which is terse and often lacking context.

The terseness is especially visible with commonly overloaded error codes like EINVAL or EIO, which occur at many places for a given syscall, or even outside the context of the current kernel call. Identifying the specific cause for the returned error using only the *errno* value requires searching for all instances that the error is returned in the kernel and trying to guess which is the most likely code path to have returned the error. **exterror** attaches additional data to the error itself and records the error category and the kernel source code file line number. The intent of **exterror** is to make it easier for a user to identify the cause of the error.

## USAGE

Before **exterror** can be used in the given source .c file, the category of extended errors must be defined. This can be done by setting the *EXTERR\_CATEGORY\_DYNAMIC* macro to a string containing the name of the file relative to *src/sys* directory. Alternatively, an entry may be allocated in the ⟨sys/exterr\_cat.h⟩ file. The category is the unique integer, that, together with the source line number, uniquely identifies the extended error occurrence. Then, the *EXTERR\_CATEGORY* symbol should be defined as an alias for the allocated category, as shown in the summary.

A typical code fragment to report an error is just

return (EINVAL);

An extended error can augment the error code with additional information:

return (EXTERROR(EINVAL, "Invalid length"));

The error data and metadata is saved in the current thread storage. The metadata includes the category and the source file line number.

Arguments to the **EXTERROR**() macro:

- The first argument to **EXTERROR**() is the errno error code.

- The second argument is a constant string with the unbound lifetime, which should tersely provide enough human-readable details about the error.

- The **EXTERROR**() macro can take two optional 64-bit integer arguments, whose meaning is specific to the subsystem. The format string may include up to two printf-like format specifiers to insert the optional argument values in the user output, which is done in userspace.

  The format specifier must be for an character, integer, or pointer type. Note that userspace printing assumes all types such as are 64-bit and prints them accordingly. Signed integer types should thus be cast to or similar to insure proper sign extension.

The strings passed as the second argument are only retained in the kernel text if the **option** **EXTERR\_STRINGS** was enabled in the kernel config. Otherwise they are stripped at compile time and are not available to userspace at runtime.

The **EXTERROR**() macro can be used in any context where the current thread is defined. Specifically, **EXTERROR**() cannot be used in interrupt contexts and context switch code. Additionally, use of **EXTERROR**() in kernel threads is not sensible as there is no userspace to retrieve the extended error data.

The **EXTERROR\_KE**() macro is similar to **EXTERROR**(), but it takes an explicit pointer *kep* to the *struct* *kexterr* to fill with the extended error information. The macro expression value is *void*. See below for description of the asynchronous i/o error facilities.

The **exterr\_clear**() function clears the content of the *struct* *kexterr* pointed to by the argument *ke*.

The **exterr\_set\_from**() function sets the current thread extended error data from the *struct*, *kexterr* pointed to by the argument *ke*.

## USERSPACE ACCESS TO EXTENDED ERROR DATA

There is no syscall overhead for using **exterror** in the non-error case. When an error occurs that has supplied extended information, the kernel copies out that information into the userspace per-thread area that was registered with the kernel, typically on image activation, or later at thread startup. The area is controlled by the exterrctl(2) internal syscall, normally done by the userspace C runtime.

Userspace programs do not need to access the extended information area directly. There is no field that is stable for the specific error condition. Instead, the base library “c” functions [err(3)](/err/3.md) and [warn(3)](/warn/3.md) were modified to print the extended information if it is available in addition to the usual *errno* decoding.

Kernels built with the **option** **EXTERR\_STRINGS** advertise the *kern.features.exterr\_strings* [sysctl(8)](/sysctl/8.md) variable, see [feature\_present(3)](/feature_present/3.md), indicating that the reported errors include the descriptive message strings. Without it, only the numeric information (error code, category, source line number and parameters) is available.

## ASYNCHRONOUS INPUT/OUTPUT

Due to the nature of the FreeBSD i/o subsystem, most input/output requests, presented as buffers (as in *struct* *buf*) and geom bio's ( *struct* *bio*) are processed asynchronously in filesystem- and geom-private threads. This makes it challenging to pass any extended error information from the geom providers and drivers, where an error typically occurs, back to the thread that initiated the request, and is the consumer of the result.

To alleviate the mismatch, both *struct* *buf* and *struct* *bio* have member of the *struct* *kexterr* type. For buffers, the *b\_exterr* for *struct* *buf*, and *bio\_exterr* for *struct* *bio*. Asynchronous i/o code can use the **EXTERROR\_KE**() macro, passing the pointer to the current request's embedded *struct* *kexterr*, to record the extended error. In both cases, the *BIO\_EXTERR* flag should be set to indicate that whole extended error is valid, not only the *b\_error* or *bio\_error* values.

Both VFS and geom generic layers, and several geom providers that generate subordinate bio's from the original request, are aware of the extended errors. They pass *kexterr* from the failed request back to the thread that create the request.

## SEE ALSO

[err(3)](/err/3.md), [errno(3)](/errno/3.md), uexterr(3), [uexterr\_gettext(3)](/uexterr_gettext/3.md)

## HISTORY

The **exterror** facility was introduced in FreeBSD 15.0.
