Polyglot
Languages MATLAB error handling
MATLAB § error-handling

Error handling

MATLAB’s error model is the conventional try/catch form found in most modern languages, with a few distinctive features: errors carry a colon-separated identifier in addition to a message; warnings are a separate, recoverable mechanism that can be selectively suppressed; and the MException class — introduced in R2007b — gives errors first-class object form. The conventional advice in modern code is to use identifiers, to construct MException objects rather than calling error with string arguments, and to reserve warning for situations that are recoverable.

Raising an error

The error function raises an error and terminates the function:

function y = sqrtCheck(x)
    if x < 0
        error("sqrtCheck:negative", "x must be non-negative; got %g", x);
    end
    y = sqrt(x);
end

The first argument — "sqrtCheck:negative" — is the identifier, a colon-separated string that programmatic callers can match against. The remaining arguments are an sprintf-style format string and its arguments. The identifier is conventional and is the basis of selective catch-by-class:

try
    sqrtCheck(-1)
catch ME
    switch ME.identifier
        case "sqrtCheck:negative"
            disp("caught the negative case")
        otherwise
            rethrow(ME)
    end
end

The function error may also be called with a single message argument, in which case the identifier is empty; that style is less useful and is discouraged.

try/catch

The block-form is conventional:

try
    riskyOperation();
catch ME
    fprintf("Caught: %s\n", ME.message)
    % optional: rethrow(ME) to propagate
end

The catch variable ME is an MException object with fields:

FieldContains
identifierColon-separated identifier ("toolbox:component:error")
messageFormatted human-readable message
stackStruct array describing the call stack
causeCell array of MException objects that caused this error
CorrectionOptional suggested correction (R2019a+)

The methods throw, throwAsCaller, rethrow, and addCause build and propagate the error appropriately. throw raises the error at the current stack frame; throwAsCaller raises it at the caller’s frame, hiding the error-utility function from the displayed stack — the convention for library helpers.

Constructing MException explicitly

For more elaborate errors, construct an MException directly:

ME = MException("solver:notConverged", ...
                "Iteration did not converge after %d steps", maxIter);
ME = ME.addCause(MException("solver:badResidual", "Residual was %g", r));
throw(ME)

The addCause chain is the equivalent of “caused by” in other languages and is preserved through the displayed error message.

Warnings

A warning is a non-fatal message that the running program issues. Warnings can be enabled or disabled — globally or per identifier — and queried after the fact:

warning("legacy:deprecation", "This function is deprecated; use newOne.");

% Caller can suppress:
warning('off', "legacy:deprecation");
oldFunction();
warning('on', "legacy:deprecation");

% Restore previous state cleanly:
ws = warning('off', "legacy:deprecation");
cleanup = onCleanup(@() warning(ws));
oldFunction();
% warning state restored when cleanup goes out of scope

The lastwarn function returns the most-recently issued warning’s message and identifier; it is useful for programmatic detection of warnings raised by library code.

onCleanup — the closest thing to RAII

onCleanup(f) creates an object that calls f when it is destroyed — which happens when it goes out of scope, including on error. The pattern is MATLAB’s analogue of C++‘s RAII destructors and Python’s with blocks:

function processFile(filename)
    fid = fopen(filename, 'r');
    if fid < 0
        error("Could not open %s", filename)
    end
    cleanup = onCleanup(@() fclose(fid));

    % ... process file; any error here triggers cleanup before propagating
end

The mechanism is the standard MATLAB idiom for guaranteeing resource release in the face of errors. The cleanup runs in the opposite order of construction; multiple onCleanup objects in the same function form a stack.

try/catch in argument validation

The arguments block (covered in Functions and scripts) raises errors when its assertions fail. The errors have the identifier MATLAB:validation:UnableToConvert or similar, and the message includes the failing argument’s name. The block is the modern alternative to defensive if/error chains and is the recommended form at function entry.

function y = doStuff(x)
    arguments
        x (1, 1) double {mustBePositive, mustBeFinite}
    end
    y = log(x);
end

doStuff(-1)
% Error using doStuff
% Invalid argument at position 1. Value must be positive.

The error is informative and uses a standardised identifier; client code can catch on "MATLAB:validators:mustBePositive".

Translating Octave-style behaviour

Code translated from GNU Octave often uses an older error/warning style with no identifier, and sometimes assumes that errors are silently catchable without try/catch. MATLAB requires the explicit construct. The translation is mechanical: wrap the section in try/catch and choose which errors to handle vs propagate.

Stack traces and the debugger

By default, errors print a multi-line stack trace. The conventional debugging tools:

  • dbstop if error — automatic breakpoint on any uncaught error.
  • dbstop if caught error — breakpoint inside the try, before the catch.
  • dbstop in functionName at lineN if condition — conditional breakpoint.
  • dbquit — exit the debugger.
  • dbup / dbdown — navigate the call stack.
  • dbcont — continue from a breakpoint.

The interactive debugger is the principal tool for diagnosing MATLAB errors; it is integrated with the editor and inspects the workspace at the point of the error.

Diagnostic best practices

  • Use identifiers. A bare error with no identifier is opaque to callers. The convention toolbox:component:detail is widespread; pick a prefix for your code and use it consistently.
  • Use arguments blocks for input validation. The block produces standardised errors with rich context and removes the burden of defensive if/error chains.
  • Use onCleanup for resource release. The pattern is robust under errors and is the cleanest analogue of RAII or with blocks.
  • Catch by identifier, not by message. Messages are localised and may change; identifiers are stable.
  • Avoid swallowing errors. A bare try/catch with an empty body silently discards every problem and is one of the most-cited anti-patterns in MATLAB code.
  • Prefer to fix the input. In numerical code, an error is often the wrong response to bad data; producing NaN or returning an empty array may be more useful. The decision is context-dependent.

A note on assert

The function assert(condition, msgFormat, ...) raises an error if the condition is false. It is occasionally useful for internal invariants — assertions that should never fail unless the code is buggy — but is not the right tool for input validation, for which arguments is cleaner.

function y = solve(A, b)
    assert(size(A, 1) == size(A, 2), "A must be square")
    y = A \ b;
end

Use assert sparingly and only where the condition reflects a programmer mistake rather than a user mistake.