# Runtime errors

> Exceptions and failures at execution — MainWindow, FrameBuffer, background thread, UI in the constructor.

Source: https://crossfly.dev/docs/troubleshooting/runtime — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Runtime errors

Format: **symptom → cause → fix**.

## `MainWindow` won't load (reflection error / "class not found")
**Cause:** the root class does not extend `Window` **or** has no public no-args constructor.
**Fix:**
```java
public class MainWindow extends Window {
   public MainWindow() { }   // no-args constructor (required for reflection)
   @Override public void onShow() throws Exception { super.onShow(); /* … */ }
}
```
([Project anatomy](/docs/get-started/project-structure))

## "FrameBuffer not disposed! Must call Image.apply after Image.getGraphics!"
**Cause:** you drew **off-screen** on an `Image` and did not commit it.
**Fix:** draw with `Image.getPaint()` and finalize with `paint.finish()` (or `image.applyChanges()`),
all inside `Main.runOnPaintThreadAndWait(...)`:
```java
Main.runOnPaintThreadAndWait(() -> {
   Paint p = img.getPaint();
   // … draw in p …
   p.finish();               // confirms (equivalent to img.applyChanges())
});
```
> ⚠️ Discrepancy: the **error message** cites `getGraphics()`/`apply()` (old names); the
> real methods are **`getPaint()`** and **`finish()`/`applyChanges()`**. (Ch. 18)

## Component changed on a background thread freezes/corrupts the UI
**Cause:** all UI manipulation is on the **paint thread**.
**Fix:** hop back with `Component.onUI(r)` / `Main.runOnPaintThread(r)`.
```java
new Thread(() -> { var v = calc(); Component.onUI(() -> label.setText(v)); }).start();
```
([The paint thread](/docs/concepts/the-paint-thread))

## UI built in the constructor shows up empty / with wrong bounds
**Cause:** in the constructor, the screen/bounds are not ready yet.
**Fix:** build it in `onShow()` with `super.onShow()`. (Ch. 7)

## Exception in `onAction` "vanishes" without crashing the app
**Cause:** handlers are caught by `Debug.handle` and **swallowed** — they don't bubble up.
**Fix:** don't rely on propagation; log (`Debug.log`/`Debug.handle`) and check `DebugConsole.txt`.
([Errors and logging](/docs/best-practices/tratamento-de-erros-e-logging))

## See also
- [Rendering problems](/docs/troubleshooting/render) · [Build and Gradle](/docs/troubleshooting/build-gradle)
