100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Error Handling with catch and try

How Tcl scripts detect, inspect, and recover from runtime errors using the catch command and the more structured try/on/finally syntax.

Advanced TclIntermediate9 min readJul 10, 2026
Analogies

Handling Errors in Tcl

By default, an uncaught error in Tcl - a missing file, a divide by zero, an undefined variable - unwinds the call stack and terminates the script with a message printed to stderr. The catch command intercepts this: catch {risky code} result stores either the successful return value or the error message in result and returns 0 on success or a non-zero code (1 for a generic error) on failure, letting a script decide how to react instead of crashing outright. Since Tcl 8.6, the try command builds on the same underlying mechanism but with clearer, block-structured syntax closer to exception handling in other languages.

🏏

Cricket analogy: catch intercepting an error before it propagates is like a wicketkeeper diving to stop a wayward throw from reaching the boundary - the play continues under control instead of conceding runs by default.

Using catch and Inspecting Errors

catch {expr {1 / 0}} err sets err to 'divide by zero' and catch returns 1; the fuller three-argument form catch {code} result optionsVar additionally populates optionsVar with a dictionary containing -errorcode, -errorinfo (the full traceback), and -errorline, letting a handler distinguish, say, a file-not-found condition from a permission-denied one by inspecting -errorcode rather than pattern-matching the human-readable message string, which can change wording between Tcl versions. The command 'error message ?info? ?code?' is how a script raises its own catchable errors, optionally supplying a custom errorcode list for callers to match on.

🏏

Cricket analogy: Matching on -errorcode rather than the message string is like an umpire's decision review checking the specific rule code violated rather than a commentator's paraphrased description of what happened.

tcl
proc safeDivide {a b} {
    if {[catch {expr {$a / $b}} result options]} {
        set code [dict get $options -errorcode]
        if {[lindex $code 0] eq "ARITH" && [lindex $code 1] eq "DIVZERO"} {
            return -code error "cannot divide $a by zero"
        }
        return -options $options $result
    }
    return $result
}

puts [safeDivide 10 2]

if {[catch {safeDivide 5 0} msg]} {
    puts "handled: $msg"
}

Structured Handling with try, on, and finally

try { risky code } on ok {result} { ... } trap {ARITH DIVZERO} {msg} { ... } finally { cleanup } reads far closer to exception handling in Python or Java than nested catch calls: 'on ok' fires only when the body succeeds, 'trap' matches a specific -errorcode pattern (with wildcards allowed at each list position), and 'finally' always executes regardless of whether an error occurred, making it the natural place for resource cleanup like closing a channel opened earlier in the same block. Multiple trap clauses can be stacked to handle different error categories with different recovery logic in one readable block instead of nested if/catch chains.

🏏

Cricket analogy: finally always running regardless of the outcome is like a ground staff's pitch-covering routine executing whether the day's play finished normally or was abandoned to rain - the tarps go on either way.

try's 'on' clause supports multiple result codes beyond 'ok', including 'error', 'return', 'break', and 'continue' - this lets a single try block react differently depending on exactly how the body exited, which is useful when the guarded code itself contains loop-control statements.

A bare 'catch {code}' with no result variable silently discards the error message entirely, only telling you that something failed via the return code - always capture at least the result variable (and ideally the options dictionary) so a failure can be logged or reported meaningfully rather than swallowed.

  • Uncaught errors unwind the stack and terminate a Tcl script by default; catch intercepts this.
  • catch {code} result returns 0 on success and a non-zero code on failure, storing the outcome in result.
  • The three-argument catch {code} result options exposes -errorcode, -errorinfo, and -errorline for detailed handling.
  • error message ?info? ?code? raises a custom, catchable error with an optional structured error code.
  • try/on/trap/finally (Tcl 8.6+) offers block-structured error handling closer to exceptions in other languages.
  • trap matches specific -errorcode patterns, allowing different recovery logic per error category.
  • finally always executes, making it the right place for guaranteed cleanup like closing channels.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#TclTkStudyNotes#ErrorHandlingWithCatchAndTry#Error#Handling#Catch#Try#ErrorHandling#StudyNotes#SkillVeris