Is there a way to define a callback function in Matlab that triggers on runtime errors?

50 views (last 30 days)
I am wondering if there is a way to create a callback function that is called everytime matlab throws an error. I know I can try/catch, but I would prefer for this to happen globally whatever script I run without having to write something like try, script, catch err, callback(err), end everytime I want to run something, also I want the callback when I use evaluate selection etc anyway.
  2 Comments
Steven Lord
Steven Lord on 8 Nov 2024 at 13:37
What are you trying to accomplish with this?
Do you want this to run even if the code catches the error and handles it itself, interposing your callback before the code the author of the function you're trying to run has specifically implemented in a catch block? [No, you don't.]
dim-ask
dim-ask on 9 Nov 2024 at 21:30
I do not want it to trigger on errors that are already caught/handled in code.
The intention:
  1. Automatically running some clean up code without having to try/catch can make some things easier in the development stage.
  2. I experiment with LLMs giving more custom feedback on errors. I made a script that sends the stack trace of the error with all the relevant context to a locally running llm, which then returns feedback on potential causes and solutions. Not necessarily sure how well something like this can work in practice, but it is fun.

Sign in to comment.

Answers (3)

Walter Roberson
Walter Roberson on 7 Nov 2024 at 21:42
Sorry, there is no way of doing this.
The most you can do is put a try/catch around the top level of your code. However, when the catch would be invoked, the call stack would already have been unwound all the way back. There is no way of putting in a general-purpose error callback that would operate at the level of individual errors.
You can set dbstop if error to stop when errors are caught -- but if you do so then you will be returned to the keyboard each time, instead of being able to program a response.

dim-ask
dim-ask on 8 Nov 2024 at 4:40
Edited: dim-ask on 8 Nov 2024 at 4:48
Ok, so I figured out a hack: set a custom callback using a timer which ticks every second or so and checks the last error using lasterror('reset') . Matlab documentation says that they do not recommend using this function because "lasterror can update its error status on any error, whether it is caught or not" but I think this only refers to using it itself inside a try/catch block, and I have not managed to make this function trigger on an error that is caught in a try/catch block elsewhere (eg trying to get it trigger by using pause inside the catch block). My intentend callback behaviour is to not handle errors that are already handled in a script, and it seems to work this way.
I am still wondering if there is any catch here, or if there is a better solution that is less hacky.
function hTimer = errHandler(dur_secs)
arguments
dur_secs (1,1) double {mustBePositive} = 60*10
end
dbstop if error % Enable stopping on errors, optional
hTimer = timer; % set up the timer
set(hTimer, 'TimerFcn', @timerRepeat);
set(hTimer, 'StopFcn', @timerCleanup);
hTimer.Period = 1; % run every second
hTimer.TasksToExecute = dur_secs; % how long to run
hTimer.ExecutionMode = 'fixedSpacing';
hTimer.start;
end
function timerRepeat(hTimer,~)
try
err_last = lasterror('reset'); % MException.last works only in command line
if strcmp(err_last.identifier, 'MATLAB:dbOnlyInDebugMode') % to prevent that weird error when exiting debug mode by pressing "stop" button after this is triggered
return
end
if any(~structfun(@isempty,err_last))
% DO STUFF HERE eg
hTimer.UserData = err_last;
end
catch err
warning(err.identifier, '%s', err.message); % prevent infinite recursion if sth goes wrong in the function
end
end
function timerCleanup(hTimer,~)
disp('Stopping Timer.')
delete(hTimer)
end

Steven Lord
Steven Lord on 10 Nov 2024 at 6:23
Depending on what exactly you want to clean up, creating an onCleanup object may be of use to you. When this object is destroyed (generally at the end of the normal operation of the function in which it is created, assuming it was not returned as an output, or when the function throws an error and so terminates unexpectedly) the function that you provided when it was created gets run.
callFunctionThatWillNotError(); % Cleanup happens at end of normal function operation
The value of x is now 1. The value of x is now 3. The value of x is now 6. The value of x is now 10. The value of x is now 15. Cleaning up now 1
callFunctionThatWillError(); % Cleanup happens before function terminates due to error
The value of x is now 1. The value of x is now [2 2;2 2]. Cleaning up now 2
Arrays have incompatible sizes for this operation.

Error in solution>callFunctionThatWillError (line 15)
x = x + ones(k);
function x = callFunctionThatWillNotError
cleanupObj = onCleanup(@() disp("Cleaning up now 1"));
x = 0;
for k = 1:5
x = x + k;
fprintf("The value of x is now %d.\n", x)
end
end
function callFunctionThatWillError
cleanupObj = onCleanup(@() disp("Cleaning up now 2"));
x = 0;
for k = 1:5
x = x + ones(k);
fprintf("The value of x is now %s.\n", mat2str(x))
end
end

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!