Quick answer: GameMaker complaining about surface stack mismatch? Some Step or Draw event throws an exception after calling surface_set_target but before surface_reset_target — the stack stays unbalanced.

An error inside a render-to-surface block leaves the surface target stack imbalanced; subsequent frames render to the wrong target.

Always Reset

surface_set_target(surf);
try {
    draw_things();
} finally {
    surface_reset_target();
}

GML has try/catch/finally. Use it around set/reset pairs so a thrown error still pops the target.

Track Depth Manually

Increment a global on each set, decrement on reset. If non-zero at end of frame, log a warning — you have a leak. Debug build-only.

Verify Surface Validity

A destroyed surface can’t be set as target; the call errors out. Check surface_exists before surface_set_target.

Avoid Nested set_target

GameMaker supports nested targets, but they make balancing harder. Flatten to single-level if possible — clearer error handling.

Verifying

Surface stack stays balanced across frames. No mismatch warnings; render targets match expectations.

“Pair every set_target with a reset_target in a finally. Stack imbalance leaks frames.”

Build a tiny wrapper with_target(surf, draw_fn) — takes a script reference, handles set/reset. No more leaks.