An operation can fail for an ordinary reason: a missing file, malformed JSON or a request rejected by an application rule. Checked errors make these outcomes part of a function’s contract. They are separate from successful results, optional absence, cancellation and fatal runtime traps.
Declare and raise an error
ERROR InvalidAge
Value AS INTEGER
END ERROR
FUNCTION ValidateAge(value AS INTEGER) AS INTEGER FAILS InvalidAge
IF value < 0 THEN
RETURN ERROR InvalidAge { Value=value }
END IF
RETURN value
END FUNCTION
TRY
PRINT ValidateAge(-3)
CATCH problem AS InvalidAge
PRINT "Invalid age: "; problem.Value
END TRY
PRINT "Continuing"FAILS lists errors that can leave the function. RETURN ERROR selects failure; ordinary RETURN selects success. Plain calls automatically check failure, even when you discard the successful result. Inline TRY on a call is optional legacy syntax, not a requirement to activate checking.
Catch here or propagate
Use TRY/CATCH when this part of the program can recover, add context or report a useful result. Otherwise declare the escaping error in the enclosing function’s FAILS clause. Merely ignoring a return value cannot hide a checked error.
ERROR MissingItem
Name AS STRING
END ERROR
FUNCTION Lookup(name AS STRING) AS STRING FAILS MissingItem
RETURN ERROR MissingItem { Name=name }
END FUNCTION
FUNCTION Title(name AS STRING) AS STRING FAILS MissingItem
RETURN UPPER(Lookup(name))
END FUNCTION
TRY
PRINT Title("report")
CATCH problem AS MissingItem
PRINT "Missing: "; problem.Name
END TRYFailure skips the remaining successful path to the matching handler or caller.
Owned locals and partial temporaries clean up. Errors thrown inside a catch go
to outer handlers or propagate, rather than re-entering a sibling catch of that
same TRY. RETURN ERROR problem forwards a caught error. Catch bindings are
read-only owners; independently copy a copyable error to edit it before forwarding.
The implicit top-level boundary reports an unhandled error after cleanup and exits
- An explicit Main still needs to declare its escaping errors. Keep lower-level functions precise; let the application boundary decide reporting policy.
Error families
ERROR OperationFailure
Message AS STRING
END ERROR
ERROR MissingDocument EXTENDS OperationFailure
Path AS STRING
END ERROR
TRY
Load()
CATCH problem AS OperationFailure
PRINT problem.Message
END TRY
SUB Load() FAILS MissingDocument
RETURN ERROR MissingDocument { Message="Cannot load", Path="notes.txt" }
END SUBCatching a parent handles descendants and exposes shared fields. Copying or forwarding a parent view preserves the concrete error and its complete payload. The common root Error has no universal Message or Code field. Prefer specific types when they let you handle the cause accurately. Broad-catch warnings show declared error sets and call/callback origins; they do not require UNSAFE.
Callback-dependent failures
A wrapper should preserve a callback’s actual checked failures, rather than silently replace them with a generic InvocationError or widen every call to Error.
ERROR SigningFailure
Message AS STRING
END ERROR
SUB Invoke(action AS CALLABLE() FAILS (Error)) FAILS LIKE action
action()
END SUB
SUB Sign() FAILS SigningFailure
RETURN ERROR SigningFailure { Message="Rejected" }
END SUB
TRY
Invoke(Sign)
CATCH problem AS SigningFailure
PRINT problem.Message
END TRYFAILS LIKE action admits the supplied callback’s checked set. The same mechanism
can follow callbacks stored in configuration records and containers. AS LIKE argument returns an owned value retaining its contained contracts; it is not a
borrowed lifetime. AS Wrapper LIKE argument carries admitted errors into a
wrapper shape. Signature references such as FAILS LIKE Decode(AS STRING) compose
contracts without executing application code. The reference part explains these
advanced forms and their limits.
What a catch cannot recover
Cancellation is a control path for stopping a task; ordinary typed CATCH does not intercept it. Fatal allocation failure, stack exhaustion, checked integer traps and direct bounds traps have no normal recoverable-cleanup promise. A missing optional value is NONE, not automatically an error. Model these distinctions in your application instead of catching Error and assuming every possible failure has become recoverable.