← Back to AILP Home

Failsafe workflow

The failsafe family is Nitpick's final safety net. v0.34.x hardens where it can be called, what shape it must have, and which runtime contract violations route through it.

Required endpoints

Every program defines main and failsafe:

func:failsafe = int32(tbb32:err) {
    exit 1;
};

func:main = int32() {
    exit 0;
};

Exit scope

v0.34.2 locks exit scope:

Diagnostic:

Failsafe must exit

v0.34.1 locks failsafe as an endpoint that cannot fall through:

func:failsafe = int32(tbb32:err) {
    if (err == 49i32) { exit 49; }
    exit 1;
};

A reachable path that returns or falls off the end is rejected with:

!!! dispatch

The !!! shorthand dispatches to failsafe and marks the path unreachable:

func:failsafe = int32(tbb32:err) {
    exit 1;
};

func:main = int32() {
    !!! 47i32;
    exit 0;
};

Use it for explicit unrecoverable paths, not ordinary Result fallback. Source expr ?! fallback remains Result fallback unwrap, not failsafe dispatch.

v0.34.x error-code table

Code Meaning
45 Existing out-of-bounds sentinel from earlier memory/bounds work.
47 kFailsafeEmphaticUnwrapErrCode, ratified from the v0.33.x reservation.
48 Contract/invariant debug runtime failure path used by v0.34.x contract checks.
49 Runtime limit<Rules> declaration/assignment violation.

The exact stdlib names live in stdlib/failsafe_codes.npk in the compiler repo.

Workflow checklist

  1. Define failsafe first in examples and tests.
  2. Keep it deterministic and side-effect-light.
  3. Match known error codes explicitly when a test needs exact behavior.
  4. End every path with exit or !!!.
  5. Use Result fail for recoverable errors; reserve failsafe for final safety net violations.

See also