Language reference
Errors and recovery
Declare expected errors and handle task execution failures.
A function can return a success value or a declared expected-error family. Write the channel after !, construct a declared error with fail and use try when propagating an error. Do not silently discard an expected-error result.
Validate and recover
error InputError:
Negative:
value: int
fn requireNonnegative(value: int) -> int ! InputError:
if value < 0:
fail InputError.Negative { value: value }
value
fn main() -> int:
requireNonnegative(-1) catch fn(error):
match error:
InputError.Negative { value }: -value This returns 1: the handler turns the rejected -1 into its positive counterpart. An early validation guard may omit else when its body ends in fail. catch receives the actual error family and must produce the original success type, or propagate through another declared channel. Payload bindings belong to their match branch.
Propagate through a helper
error InputError:
Negative
fn validated(value: int) -> int ! InputError:
if value < 0: fail InputError.Negative
value
fn adjusted(value: int) -> int ! InputError:
result = try validated(value)
result + 2
fn main() -> int:
adjusted(40) catch fn(error): 0 This returns 42. try in adjusted propagates InputError; the call in main handles it if validation fails.
Task errors are a separate channel
CPU and GPU worker execution can fail independently of application validation. parallelMap and spawn/await therefore expose TaskError as well as any application-defined errors from the work. Error unions use the spelling ! (InputError | TaskError).
Checked arithmetic, bounds, shape and allocation faults are execution failures rather than implicit application variants. Handle a TaskError at a task boundary when you need recovery. An application-only handler does not swallow unrelated execution faults.
Recover from a GPU task
A GPU function can declare an application-error family. It can handle the error on the device or return it to the task's caller. An await exposes the declared family together with TaskError.
error InputError:
Negative:
value: int
fn validate(value: int) -> int ! InputError:
if value < 0:
fail InputError.Negative { value: value }
value
fn main() -> int ! TaskError:
try parallel:
result = await spawn validate(-42) on devices.gpu()
result catch fn(error):
match error:
InputError.Negative { value }: -value
_: 0 The handler recovers the value 42. The GPU executable prints it as 000000000000002a. The final match arm supplies a fallback for TaskError in this example. An application error handled inside the group leaves other children running. Propagating the error out of the group cancels unfinished siblings and waits for them to settle.
Payloads can contain numeric and Bool values, supported records and enums, and supported arrays and tensors. The compiler rejects host-only fields such as String and task handles in a device error payload. TaskError belongs to the task boundary. Checked arithmetic and bounds faults bypass device-local application handlers.
Choose a recovery policy
Handle specific variants when different failures need different policies. A catch-all fallback is appropriate only when every error truly has the same meaning to the application. Parallel groups settle unfinished children before leaving; completed effects are not rolled back, and racing failures need not select a deterministic winner.
TaskError variants
TaskError.Fault carries kind and message. The kind is a FaultKind value: Arithmetic, Bounds, Shape, Allocation or Native. The message is a String describing the failure; do not parse it as a stable error code.
TaskError.Cancelled means task cancellation. TaskError.DeadlineExceeded means a task deadline was exceeded. TaskError.AdmissionRejected carries a reason String when work could not be admitted. These variants describe task outcomes. There is no source-level API for configuring every deadline or resource policy.
Match a variant to bind its fields, or use a catch-all handler when every failure has the same recovery. Only the active variant's fields are available. Task errors can be combined with application-error families using an error union.