# Failure isolation

> What happens when your menu code throws - which failures turn only your menu off, which are just logged, and how mistakes in builders show up.

URL: https://xichil.dev/docs/xis-mvui/v1/concepts/failure-isolation/ · Updated: 2026-11-06 · Applies to: Fabric, Quilt, Legacy Fabric, Forge, NeoForge, MC 1.7.10 - 26.3

Any number of mods can register menus, and one mod's bug never breaks another's, or the game. What happens
depends on where your code throws.

## The three outcomes

| Your code throws in… | Result |
| --- | --- |
| `ScreenFactory.create` or `buttonLabel`, or **any supplier** (label, value, `enabled`, `visible`, tooltip, rows, validator), or `create` returns `null` | **Your menu turns off for the rest of the session.** The error is logged once, naming your mod. Other mods' menus keep working. |
| **an action**: `onPress`, `onChange`, `onSelect`, `onToggle`, a dialog answer, a `runOnMainThread` task, a `runAsync` callback | **The error is logged** with your mod id, and the menu stays open. |
| a builder's `build()` (a missing required field, a bad id, a bad range) | **It throws at once**, with a message naming the widget and the field, so it shows up in development. |

A `runAsync` *task* that throws is none of these: its exception goes to your `onDone` as the second argument.

## What players see when your menu is off

- Opening your menu shows a screen saying: "This menu stopped after an error and is off until the game
  restarts. The game log has the details."
- In the "Mod menus" list, your button is greyed out with that text as its tooltip.
- `MultiversionUi.menuScreen("mymod", parent)` returns that same screen.

The log line looks like this, followed by the stack trace:

```text
[Xi's Multiversion UI Lib] ERROR Building the first screen of mymod's menu failed in mod mymod's menu code: its menu is off until the game restarts. Other mods' menus still work.
```

## Your exceptions stay yours

The library doesn't wrap your exceptions. Your own `catch` blocks receive them unchanged; the library only adds
a suppressed entry to the stack trace that names your mod, which is how it knows whose menu to turn off.

## When the library itself fails

If one of the library's own hooks throws, for example because a Minecraft update renamed something, every
mod's menu turns off for the session and the error is logged once. The game and every mod keep running; they
just have no menus. Screens that are already open stay usable, so the player can leave them.

## Write code that doesn't turn off

- Keep suppliers trivial: read a field, format a string. Do the risky part in an action or in `runAsync`, where
  a failure is only logged.
- Catch expected errors in actions and show them in a [StatusLine](https://xichil.dev/docs/xis-mvui/v1/widgets/status-line/index.md) instead of
  letting them reach the log.
- Check `Failsafe.enabled("mymod")` if you need to know whether your menu is still on, and `Failsafe.enabled()`
  for the library as a whole. See [Failsafe](https://xichil.dev/javadoc/xis-mvui/v1/dev/xichil/mvui/Failsafe.html).

## Testing the failure path

| JVM flag | Effect |
| --- | --- |
| `-Dxis_mvui.forceError=true` | every library hook fails, to test that the game survives with menus off |
| `-Dxis_mvui.disable=true` | turns the library off: no backend, no menus |

In unit tests with `FakeHost`, an unregistered menu isn't guarded at all, so your exception reaches the test
directly.

## Next steps

- [Threads](https://xichil.dev/docs/xis-mvui/v1/concepts/threads/index.md): where each kind of code runs.
- The wiki's [troubleshooting page](https://xichil.dev/wiki/xis-mvui/v1/troubleshooting/index.md), for what players can do.
