09 · Debugging in MATLAB¶
Verification note
MATLAB was not available in the environment used to write this page.
Debugger command names (dbstop, dbstep, dbcont...) and their
behavior are documented MATLAB features, hand-traced against the
MATLAB debugging documentation rather than exercised in a live
debugger session.
Reading error messages carefully and knowing MATLAB's interactive debugger turns "my script crashed" from a guessing game into a systematic process. This module covers both.
Reading a MATLAB error, top to bottom¶
Error using *
Inner matrix dimensions must agree.
Error in computeForces (line 14)
F = M * a;
Error in simulate (line 27)
forces = computeForces(mass, accel);
Read the stack from bottom to top to trace how execution got there,
but read the top error message first — it names the actual failure
(* with mismatched dimensions). Error in computeForces (line 14)
means line 14 of computeForces.m is where the failing operation lives;
Error in simulate (line 27) is the calling line one level up. For a
deep stack, the first frame (closest to the actual Error using ...
line) is almost always where the real bug is — outer frames just show
how you got there.
A very common mistake is to start debugging at the outermost frame
(simulate) instead of the innermost (computeForces, line 14) — check
size(M) and size(a) at that innermost line first.
dbstop: breakpoints from the command line¶
Setting a breakpoint in the Editor (clicking the margin) is one way;
dbstop is the command-line equivalent, useful in scripts, from a remote
session, or for conditional breaks the Editor UI doesn't expose as
easily:
dbstop in computeForces at 14 % break at a specific line
dbstop in computeForces at 14 if any(isnan(a)) % conditional breakpoint
dbstop if error % break automatically at any uncaught error
dbstop if naninf % break the instant a NaN/Inf is produced
dbstop if error is one of the most useful blanket debugging commands —
rather than reading a stack trace after the fact, it drops you into the
debugger at the moment of the crash, with every local variable still in
scope to inspect, before MATLAB unwinds the stack.
Once stopped, the prompt changes to K>> and normal commands operate in
the paused function's own workspace:
Stepping commands¶
| Command | Shortcut | Effect |
|---|---|---|
dbstep |
F10 | Execute the current line, stop at the next |
dbstep in |
F11 | Step into a function call on the current line |
dbstep out |
Shift+F11 | Run until the current function returns |
dbcont |
F5 | Resume running until the next breakpoint (or completion) |
dbquit |
Shift+F5 | Abort debugging entirely, return to base workspace |
dbstep vs dbstep in is the distinction that matters most: if the
current line calls a function you already trust (e.g. a well-tested
utility), use dbstep to skip over it as one unit; if you suspect the
bug is inside that call, use dbstep in to follow execution into it.
dbstack and dbup/dbdown¶
While paused, dbstack prints the current call stack; dbup/dbdown
move your inspection context one frame up or down the stack without
resuming execution — useful to check a caller's variables while still
stopped inside a deeply nested function:
K>> dbstack
> In computeForces at 14
In simulate at 27
K>> dbup % now inspecting simulate's workspace
K>> mass % see the value simulate passed in
K>> dbdown % back to computeForces's workspace
Removing breakpoints¶
dbclear all % remove every breakpoint everywhere
dbclear in computeForces % remove all breakpoints in one file
dbstatus % list every currently set breakpoint
Forgetting to dbclear a conditional breakpoint before handing off a
script is a common source of "why does this randomly stop for my
teammate" — dbstatus at the end of a debugging session is a good habit
before saving/committing code.
The Editor's visual debugger¶
Everything above has an Editor equivalent: click the margin next to a
line number to toggle a breakpoint (a red dot appears); run the script
normally and execution pauses there with the line highlighted; the
toolbar's step/step-in/step-out/continue buttons mirror
dbstep/dbstep in/dbstep out/dbcont. The Workspace panel while
paused shows every variable in the current stopped scope, which is often
faster for casual inspection than typing variable names at K>>.
Common bug categories and how to localize them¶
Dimension mismatches — the single most frequent MATLAB runtime
error. dbstop if error, then at the point of failure:
almost always immediately reveals whether a transpose (') is missing,
a loop index went one too far, or a function returned a different shape
than expected.
Off-by-one indexing — MATLAB is 1-indexed; a loop written with
0-indexed habits from another language either errors (Index exceeds
array bounds, when using index 0) or silently reads/writes the wrong
element (length(x)+1, going one past the end and growing the array
instead of erroring — a much sneakier bug since MATLAB happily
auto-extends arrays on assignment).
x = [10 20 30];
x(4) = 99; % no error! silently extends x to [10 20 30 99]
x(0) % this one *does* error: "Index must be a positive integer"
Print size(x) before and after suspicious loop bodies when values seem
to silently grow.
Wrong function shadowing another — from module 08's which -all:
if a variable is accidentally named the same as a function (sum = 5;
followed later by sum(x)), MATLAB resolves the variable first, and
subsequent calls to sum(x) error with Index exceeds array bounds or
similar, since sum is no longer callable as a function in that scope.
which sum (or clear sum) diagnoses this immediately.
NaN propagation — using dbstop if naninf catches the exact line
where a NaN or Inf is first produced, rather than debugging its
downstream symptoms (a garbage plot, a polyfit warning) several
function calls later.
A worked debugging session¶
function out = process(data)
normalized = (data - mean(data)) / std(data);
out = normalized.^2;
end
x = process([]); % empty input by mistake somewhere upstream
Calling process([]) produces mean([]) = NaN (mean of empty is
NaN by MATLAB convention), silently propagating to out as all-NaN with
no error at all — a classic silent-failure bug that a stack trace won't
catch since nothing actually throws. dbstop if naninf set before
calling process would break the instant mean([]) produces NaN,
right at the true source, rather than downstream where the all-NaN
result eventually causes a confusing plot or fit failure.
How It Actually Works¶
Setting a breakpoint doesn't pause "the CPU" — it inserts a flag into MATLAB's interpreter loop that checks, before executing each source line in debug-eligible code, whether that line has an active breakpoint; if so, the interpreter suspends normal execution and drops you into a nested interactive session that shares the paused function's workspace. This is mechanically why you can inspect and even reassign local variables at a breakpoint and have execution continue with the new values — you are still inside that function's actual workspace, not looking at a snapshot or copy of it. It's also why breakpoints inside functions that have been JIT-compiled to native code can subtly change timing or, in some cases, force MATLAB to fall back to interpreted execution for that function while a breakpoint is active — debug hooks and aggressive native-code compilation are in tension, so MathWorks documents that stepping through JIT-eligible code can behave slightly differently than running it uninterrupted.
The dbstack call and the debugger's call-stack display both walk the
same underlying call stack structure MATLAB maintains for every
function invocation (needed anyway for error stack traces and MException
objects) — a debugger doesn't need a separate bookkeeping system, it's
reading live interpreter state that already exists to support normal error
reporting.
try/catch and breakpoints interact in a specific way worth knowing:
setting "stop on errors" makes MATLAB break before a catch block would
otherwise silently handle the exception, which is genuinely useful for
diagnosing errors that a well-meaning try/catch is currently masking
during development.
Note: reasoned from MATLAB's documented debugger and interpreter architecture; not exercised in a live debugging session, since MATLAB is unavailable in this environment.
Summary¶
- Read the error's top line for what failed, the stack bottom-up for how you got there; start inspecting at the innermost frame.
dbstop if error(break at the crash site) anddbstop if naninf(break the instant a NaN/Inf appears) are the two highest-value blanket breakpoints for most numerical bugs.dbstepvsdbstep invsdbstep out— skip, follow, or exit a call, respectively — anddbup/dbdownto inspect other frames without resuming.- Dimension mismatches, off-by-one/auto-extending array indexing, and
silent NaN propagation account for the large majority of real-world
MATLAB bugs; each has a specific debugger habit (
size, watch array length,dbstop if naninf) that finds it fast.