Error Handling in Depth — Clean Language
← All tutorials
language-deep-dive7 min

Error Handling in Depth

Clean Language has a direct, explicit error system. You signal errors with error() and handle them at the call site with onError. Errors are visible in the code — you decide exactly where they are caught and what the fallback is, with no hidden exception stacks.

Signal errors with error() and catch them with onError at the call site:

functions:\n    number safe_divide(number a, number b)\n        if b == 0.0\n            error("Division by zero")\n        return a / b\n\nstart:\n    number good = safe_divide(10.0, 2.0)\n    print("10 / 2 = " + good.toString())\n\n    number safe = safe_divide(10.0, 0.0) onError -1.0\n    print("10 / 0 = " + safe.toString() + " (used fallback)")
10 / 2 = 5.0\n10 / 0 = -1.0 (used fallback)

error("message") signals an error from inside a function. At the call site, appending onError VALUE provides a fallback — if the function errors, you get the fallback value instead of crashing. Each call site decides its own fallback independently.

Chain validation and onError to build robust parsers:

functions:\n    integer parse_age(string input)\n        if input.length() == 0\n            error("Age cannot be empty")\n        integer age = input.toInteger() onError -1\n        if age < 0\n            error("Age must be positive")\n        if age > 150\n            error("Age is unrealistically high")\n        return age\n\nstart:\n    integer a = parse_age("28")\n    print("Valid: " + a.toString())\n\n    integer b = parse_age("") onError 0\n    print("Empty fallback: " + b.toString())\n\n    integer c = parse_age("abc") onError 0\n    print("Invalid fallback: " + c.toString())
Valid: 28\nEmpty fallback: 0\nInvalid fallback: 0

onError can be used on any expression, including another onError result. input.toInteger() errors on non-numeric input, and onError -1 catches it; then if age < 0 signals a new error, caught by the caller. This chains validation naturally.

Quick recap

  • error("message") signals an error — execution stops at that point in the function
  • function() onError VALUE provides a fallback if the function signals an error
  • onError is local — each call site decides its own fallback independently
  • Chain onError: toInteger() onError -1 converts parse failures to a sentinel value
Copied!