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:
| Field | Contains |
|---|---|
identifier | Colon-separated identifier ("toolbox:component:error") |
message | Formatted human-readable message |
stack | Struct array describing the call stack |
cause | Cell array of MException objects that caused this error |
Correction | Optional 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 thetry, before thecatch.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:detailis widespread; pick a prefix for your code and use it consistently. - Use
argumentsblocks for input validation. The block produces standardised errors with rich context and removes the burden of defensiveif/errorchains. - Use
onCleanupfor resource release. The pattern is robust under errors and is the cleanest analogue of RAII orwithblocks. - Catch by identifier, not by message. Messages are localised and may change; identifiers are stable.
- Avoid swallowing errors. A bare
try/catchwith 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
NaNor 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.