# Assertions and Argument Checking (/contributing/assertions)



LVGL provides two sets of macros for validating conditions at runtime:
**assertions** and **argument checking**. This page explains when and how to use
each within LVGL's codebase. If you are using LVGL rather than contributing to
it, see [Argument Checking](/debugging/argument_checking) for what these checks
mean for your application and how to configure them.

Overview [#overview]

| Feature           | LV\_ASSERT                  | LV\_CHECK\_ARG         |
| ----------------- | --------------------------- | ---------------------- |
| Purpose           | Catch programming errors    | Validate runtime input |
| On failure        | Halts (LV\_ASSERT\_HANDLER) | Configurable action    |
| Log level         | Error                       | Warning                |
| Recovery possible | No                          | Yes / Maybe            |
| Typical use       | Internal invariants         | API input validation   |

**Use assertions** for conditions that indicate bugs in the code, situations
that should never happen if the code is correct. If an internal function expects
a parameter to satisfy a certain condition, add an assertion: it acts as
executable documentation for future contributors and catches misuse early.

**Use argument checking** for validating inputs at public API boundaries.
`LV_CHECK_ARG` (and `LV_CHECK_OBJ*`) are **mandatory** at the start
of every public API function, they allow callers to recover gracefully and
produce actionable log output when something goes wrong.

***

Assertions [#assertions]

Assertions check for programming errors and halt the program when they fail.
They are typically enabled only in debug builds and may be disabled in release builds.

Configuration [#configuration]

Enable assertions in `lv_conf.h`:

* <ApiLink name="LV_USE_ASSERT_NULL" /> - Check for NULL pointers
* <ApiLink name="LV_USE_ASSERT_MALLOC" /> - Check for failed memory allocations
* <ApiLink name="LV_USE_ASSERT_MEM_INTEGRITY" /> - Check memory integrity

Configure the assert handler with <ApiLink name="LV_ASSERT_HANDLER" />. The default
behavior is `while(1);` which halts the program.

Usage [#usage]

<ApiLink name="LV_ASSERT" />

Basic assertion with the condition stringified in the log message:

```c title=" " lineNumbers=1
LV_ASSERT(pi > 0);
```

<ApiLink name="LV_ASSERT_MSG" />

Assertion with a plain string message:

```c title=" " lineNumbers=1
LV_ASSERT_MSG(pi > 0, "pi should be positive");
```

<ApiLink name="LV_ASSERT_FORMAT_MSG" />

Assertion with a printf-style format message:

```c title=" " lineNumbers=1
LV_ASSERT_FORMAT_MSG(pi > 0, ": was %f", pi);
```

Specialized Assertions [#specialized-assertions]

<ApiLink name="LV_ASSERT_NULL" />

Check that a pointer is not NULL:

```c title=" " lineNumbers=1
LV_ASSERT_NULL(obj);
```

<ApiLink name="LV_ASSERT_MALLOC" />

Check that a memory allocation succeeded:

```c title=" " lineNumbers=1
void * buf = lv_malloc(size);
LV_ASSERT_MALLOC(buf);
```

<ApiLink name="LV_ASSERT_MEM_INTEGRITY" />

Check that LVGL's memory pool is not corrupted:

```c title=" " lineNumbers=1
LV_ASSERT_MEM_INTEGRITY();
```

***

Argument Checking [#argument-checking]

The <ApiLink name="LV_CHECK_ARG" /> macro provides a flexible approach for validating
function arguments at runtime: it logs a warning and allows you to specify a
recovery action (such as returning from a function or continuing with a fallback).

This macro is useful for:

* Input validation at the start of functions
* Checking preconditions without halting the program
* Defensive programming with graceful error handling
* Logging invariant violations that may not be critical but should be noted

Configuration [#configuration-1]

* <ApiLink name="LV_USE_CHECK_ARG" /> — Set to `1` to enable, `0` to disable.
  Enabled by default.
  When disabled, all `LV_CHECK_ARG` and `LV_CHECK_OBJ` calls compile to nothing.

  <Callout type="warning" title="Disabling argument checks is dangerous">
    With `LV_USE_CHECK_ARG = 0`, passing invalid arguments to any public API
    function is undefined behavior — there is no NULL guard, no type check, and
    no early return. Only disable this if you can guarantee that every call site
    in your application passes valid arguments. When in doubt, leave it enabled.
  </Callout>

* <ApiLink name="LV_CHECK_ARG_ASSERT_ON_FAIL" /> — Set to `1` to also call
  `LV_ASSERT_HANDLER` on failure (before the action is executed). Useful during
  debugging to restore hard-abort behavior.

* <ApiLink name="LV_CHECK_ARG_LOG_MODE" /> — Controls how much is logged when a
  check fails. Requires `LV_USE_LOG = 1`; if logging is disabled no output is
  produced regardless of this setting.
  * `LV_CHECK_ARG_LOG_MODE_NONE (0)` — No log output.
  * `LV_CHECK_ARG_LOG_MODE_MINIMAL (1)` — Logs `"Check failed"` plus file and line number.
  * `LV_CHECK_ARG_LOG_MODE_VERBOSE (2)` — Logs `"Check failed: <cond>"` plus any caller-supplied message.

Usage [#usage-1]

<ApiLink name="LV_CHECK_ARG" /> takes a condition and an action to execute on
failure. <ApiLink name="LV_CHECK_ARG_MSG" /> also takes a message and
<ApiLink name="LV_CHECK_ARG_FORMAT_MSG" /> a printf-style format string with its
arguments:

```c title=" " lineNumbers=1
void draw_to_display(lv_obj_t * display, int len)
{
    /* Return early if display is NULL */
    LV_CHECK_ARG_MSG(display != NULL, return, "display must be provided");

    /* Return if len is invalid, logging the actual value */
    LV_CHECK_ARG_FORMAT_MSG(len % 2 == 0, return, "need even data points, but got %d", (int)len);
}

int get_width(lv_obj_t * obj)
{
    /* Return -1 if obj is NULL */
    LV_CHECK_ARG(obj != NULL, return -1);
    /* ... */
}
```

The condition is stringified and included in the log message, so you can see
exactly what check failed. Only supply a message, or a format string and
arguments, if you want to include additional context beyond the condition
itself.

***

Object Checking [#object-checking]

<ApiLink name="LV_CHECK_OBJ" /> is the standard replacement for `LV_ASSERT_OBJ` and
the only object-checking macro you should use directly. It performs all checks
enabled by the configuration (see below) and requires
<ApiLink name="LV_USE_CHECK_ARG" /> `= 1`:

```c title=" " lineNumbers=1
LV_CHECK_OBJ(obj, &lv_label_class, return);
```

<ApiLink name="LV_CHECK_OBJ_CLASS" /> and <ApiLink name="LV_CHECK_OBJ_VALID" /> are
lower-level building blocks exposed for completeness. Do not use them directly.

Configuration [#configuration-2]

The checks performed by <ApiLink name="LV_CHECK_OBJ" /> macros are layered and independently configurable:

| Layer      | Config option                    | What it checks                                                                               |
| ---------- | -------------------------------- | -------------------------------------------------------------------------------------------- |
| Base       | `LV_USE_CHECK_ARG = 1`           | Master switch. When `0`, all three macros expand to nothing.                                 |
| NULL       | always on                        | `obj != NULL` (always checked when the system is enabled).                                   |
| Class type | `LV_USE_CHECK_OBJ_CLASSTYPE = 1` | `lv_obj_has_class(obj, cls)` — verifies the object is the expected widget type.              |
| Validity   | `LV_USE_CHECK_OBJ_VALIDITY = 1`  | `lv_obj_is_in_widget_tree(obj)` — verifies the object is still part of the live widget tree. |

`LV_USE_CHECK_ARG` defaults to `1`; both `LV_USE_CHECK_OBJ_*` options default
to `0`. Enable them selectively:

```c title=" " lineNumbers=1
/* lv_conf.h */
#define LV_USE_CHECK_ARG            1   /* master switch — enables LV_CHECK_ARG and LV_CHECK_OBJ* */
#define LV_USE_CHECK_OBJ_CLASSTYPE  1   /* also verify the object's class type */
#define LV_USE_CHECK_OBJ_VALIDITY   1   /* also verify the object is alive in the widget tree */
```

<Callout type="warning" title="Enable only during development">
  `lv_obj_is_in_widget_tree()` walks the widget tree and `lv_obj_has_class()` traverses
  the class hierarchy on every call site. These checks add non-trivial overhead,
  especially in rendering-critical code paths. Keep `LV_USE_CHECK_OBJ_CLASSTYPE`
  and `LV_USE_CHECK_OBJ_VALIDITY` at `0` in production builds.
</Callout>

***

Macros Reference [#macros-reference]

Assertions [#assertions-1]

| Macro                                      | Description                               |
| ------------------------------------------ | ----------------------------------------- |
| <ApiLink name="LV_ASSERT" />               | Assert condition; on failure log and halt |
| <ApiLink name="LV_ASSERT_MSG" />           | Assert with plain string message          |
| <ApiLink name="LV_ASSERT_FORMAT_MSG" />    | Assert with printf-style format message   |
| <ApiLink name="LV_ASSERT_NULL" />          | Assert pointer is not NULL (if enabled)   |
| <ApiLink name="LV_ASSERT_MALLOC" />        | Assert allocation succeeded (if enabled)  |
| <ApiLink name="LV_ASSERT_MEM_INTEGRITY" /> | Assert memory pool integrity (if enabled) |

Argument Checking [#argument-checking-1]

| Macro                           | Description                                        |
| ------------------------------- | -------------------------------------------------- |
| <ApiLink name="LV_CHECK_ARG" /> | Check condition; on failure log and execute action |

Object Checking [#object-checking-1]

| Macro                                 | Description                                                                     |
| ------------------------------------- | ------------------------------------------------------------------------------- |
| <ApiLink name="LV_CHECK_OBJ" />       | NULL + optional class type + optional validity check (preferred)                |
| <ApiLink name="LV_CHECK_OBJ_CLASS" /> | NULL + optional class type check                                                |
| <ApiLink name="LV_CHECK_OBJ_VALID" /> | NULL + optional class type + optional validity check (alias for `LV_CHECK_OBJ`) |
