89
$\begingroup$

Mathematica is a bit unusual as a programming language because it never stops on messages, regardless of whether the message is an error, a warning or just an informative message. It simply prints the message and continues with evaluation. This can cause an avalanche of messages and unpredictable behaviour (e.g. memory may get filled up, bringing the machine to a halt with swapping---this is what happened to me)

Is there a way to immediately abort when any message is generated?

Requirements:

  1. if a message would be printed, always abort.
  2. if no message would be printed, don't abort.
  3. do print the first message so I have a hint about what went wrong
  4. the mechanism should work with parallel computations and should abort the full evaluation (i.e. main kernel and all parallel kernels)

There are many ways to handle message printing, including On/Off, Quiet, and possibly others (such as setting some system options). The solution should work well with these. I am afraid manually handling all possible situations is too fragile (there's always a chance something got left out).

I found a solution on MathGroup which aborts, but does not print the message.

I suspect there must exist a robust and simple solution because the Debug palette has a "Break on messages" option.

$\endgroup$
1

6 Answers 6

84
$\begingroup$

I found a robust solution described in this MathGroup message by Maxim Rytin:

messageHandler = If[Last[#], Abort[]] &

Internal`AddHandler["Message", messageHandler]

This will abort the computation whenever a message would be printed.

It can be turned off using

Internal`RemoveHandler["Message", messageHandler]

Alternatively this can be temporarily applied to a piece of code like this:

Internal`HandlerBlock[
 {"Message", messageHandler},
 (* ... code here ... *)
]

The currently set message handlers can be retrieved using

Internal`Handlers["Message"]

(Internal`Handlers[] will return all existing handlers)

Whenever a message is generated, Hold[message, printed] is passed to all "Message" handler functions where message is the message text and printed is True is the message would be printed, False otherwise.

The debugging palette appears to use the same mechanism to break on messages.


To make it work with parallel evaluations, one can simply register the same handler on all kernels using ParallelEvaluate.

$\endgroup$
2
  • 2
    $\begingroup$ Caveat: functions such as Reduce, Refine and Solve can pass messages to handlers which have printed=True but are somehow never printed. These include FindMinimum::fmmp and N::meprec, which I'm guessing are harmless. $\endgroup$ Commented Mar 28, 2013 at 2:14
  • 3
    $\begingroup$ This functionality has made its way into a top-level function (sorta) with GeneralUtilities`WithMessageHandler which turns messages into Failure objects. $\endgroup$
    – b3m2a1
    Commented Dec 12, 2016 at 16:17
19
$\begingroup$

What about something like this?

Function[i, {i, ParallelEvaluate[i]};, HoldFirst][
 Unprotect[Message, Check, Quiet];
 Module[{$guardMes = True, $guardChck = True, $guardQuiet = True},
  Message[args___ /; $guardMes] := Block[{$guardMes = False},
    Message[args];
    If[Head[First@{args}] =!= $Off, Abort[]];
    ];
  Quiet[args___ /; $guardQuiet] := Block[{$guardQuiet = False, $guardMes = False},
     Quiet[args]
    ];
  Check[args___ /; $guardChck] := Block[{$guardChck = False, $guardMes = False},
     Check[args]
    ];
  ]
 ]

EDIT to try to reflect Szabolcs's and Sjoerd's concerns

Function[i, {i, ParallelEvaluate[i]};, HoldFirst][
  Module[{$guardMes = True},
    OnMessageAbort[] := (
      Unprotect[Message];
      Message[args___ /; $guardMes && Head[First@{args}] =!= $Off] :=          
       Block[{$guardMes = False, flag = False},
        Internal`InheritedBlock[{$MessagePrePrint},
         $MessagePrePrint = 
          With[{fn = $MessagePrePrint}, 
           Function[i, flag = True; fn[i], HoldAll]];
         Message[args];
         If[flag, Abort[];]
         ]
        ];
       Protect[Message]);
    OffMessageAbort[] := (
      Unprotect[Message];
      Quiet[
       Message[args___ /; $guardMes && Head[First@{args}] =!= $Off] =.];
      Protect[Message];
      )
    ];
  ];
OnMessageAbort[ker_] := ParallelEvaluate[OnMessageAbort[], ker];
OnMessageAbort[All] := (ParallelEvaluate[OnMessageAbort[]]; 
   OnMessageAbort[]);
OffMessageAbort[ker_] := ParallelEvaluate[OffMessageAbort[], ker];
OffMessageAbort[All] := (ParallelEvaluate[OffMessageAbort[]]; 
   OffMessageAbort[]);

You run that once, and it defines (On/Off)MessageAbort[] in all kernels. You can call OnMessageAbort[] to turn it on on the kernel you run that, or OnMessageAbort[kernel] from the main kernel to turn it on on a particular kernel, just like the second argument to ParallelEvaluate. OnMessageAbort[All] turns it on in all of them. Same goes for OffMessageAbort

$\endgroup$
9
  • $\begingroup$ I just used ParallelEvaluate instead of DistributeDefinitions, and now it works fine in parallel too. I have some ideas why DistributeDefinitions doesn't work here, but the workaround is good enough for now. Please also see groups.google.com/d/msg/comp.soft-sys.math.mathematica/… $\endgroup$
    – Szabolcs
    Commented Feb 8, 2012 at 18:53
  • $\begingroup$ Edited with ParallelEvaluate and as you said it works. Thanks for the link $\endgroup$
    – Rojo
    Commented Feb 8, 2012 at 18:56
  • $\begingroup$ @Szabolcs, reading your question on your link, when you do x=1;ParallelEvaluate[x], it returns {1,1} because your main kernel evaluates the result {x,x} returned from the parallel kernels, not because x was automatically synched $\endgroup$
    – Rojo
    Commented Feb 8, 2012 at 19:16
  • $\begingroup$ Thanks for pointing this out, you are right, ParallelEvaluate does not auto-sync (ParallelEvaluate@Hold@Evaluate[x] can be used for testing). But Parallelize does auto-distribute definitions, so my original problem that I asked about was valid :-) $\endgroup$
    – Szabolcs
    Commented Feb 8, 2012 at 19:24
  • $\begingroup$ +1, good stuff! My version does not yet quite work for parallel, and your does. Nice! $\endgroup$ Commented Feb 8, 2012 at 19:37
16
$\begingroup$

The easiest and, so far, the best solution I have found is the following:

(* Put the following two lines at the top of every notebook. *)
messageHandler = If[Last[#], Interrupt[]] & ;
Internal`AddHandler["Message", messageHandler];

The above code is slightly modified from Szabolcs's solution at the beginning of this thread. I changed Abort to Interrupt. The latter seems to work immediately, while it appears that Abort may be waiting for some portion of the evaluation to finish before stopping everything.

$\endgroup$
2
  • $\begingroup$ Hi Ralph, thanks for the answer! I formatted your code for you. If you would like more information about how to do this yourself, have a look at this page. $\endgroup$
    – Verbeia
    Commented Aug 9, 2012 at 6:21
  • $\begingroup$ Thank you verbeia! As you correctly surmised, I could not figure out how to get the code to look right. $\endgroup$ Commented Aug 10, 2012 at 11:46
13
$\begingroup$

I've written a function CheckReturn that attempts to behave just like Check, except that it returns immediately if a message is generated. Also, if Quiet wrappers are used external or internal to CheckReturn, the behavior is consistent with how Check works. The code is given at the end. Here are some examples:

CheckReturn[1/0; Print[2], $Failed]
Check[1/0; Print[2], $Failed]

Power::infy: Infinite expression 1/0 encountered.

$Failed

Power::infy: Infinite expression 1/0 encountered.

2

$Failed

Notice that using CheckReturn, 2 was not printed. So far so good. Now, let's use an external Quiet:

Quiet @ CheckReturn[1/0; Print[2], $Failed]
Quiet @ Check[1/0; Print[2], $Failed]

$Failed

2

$Failed

In both cases the message is detected and failure expression is returned, but CheckReturn returns immediately without printing 2. Similarly, if we use an internal Quiet:

CheckReturn[ Quiet[1/0]; Print[2], $Failed]
Check[ Quiet[1/0]; Print[2], $Failed]

2

2

In both cases the internal Quiet is respected, and the message is not detected. CheckReturn has the option "CheckQuietedMessages"->False. If we set this option to True, than the internal Quiet is disregarded:

CheckReturn[ Quiet[1/0]; Print[2], $Failed, "CheckQuietedMessages"->True ]

Power::infy: Infinite expression 1/0 encountered.

$Failed

Just like Check has a 3-arg version where explicit messages can be specified, the same is possible with CheckReturn:

CheckReturn[ 1/0; Print[2], $Failed, Power::infy ]

Power::infy: Infinite expression 1/0 encountered.

$Failed

Finally, if messages are turned off, than CheckReturn ignores them as well:

Off[Power::infy]
CheckReturn[ 1/0; Print[2], $Failed, Power::infy]
Check[1/0; Print[2], $Failed, Power::infy]

2

2

Note that I didn't consider parallel behavior. Here is the code:

SetAttributes[CheckReturn,HoldAll]
Options[CheckReturn]={"CheckQuietedMessages"->False};

CheckReturn[body_,return_, OptionsPattern[]] := Module[{handler,flag},
    With[{stack = If[TrueQ@OptionValue["CheckQuietedMessages"], _, quietStack[]]},
        handler[Hold[mess_Message, True]]:=Throw[$Failed,flag];
        handler[Hold[mess:Message[mn_,___], False]] /; quietedMessageCheck[HoldForm[mn],stack] := Throw[
            Hold[mess],
            flag
        ]
    ];

    Catch[
        Internal`HandlerBlock[{"Message",handler},body],
        flag,
        (ReleaseHold[#];return)&
    ]
]

CheckReturn[body_, return_, m_, OptionsPattern[]]:=Module[{pred,handler, flag},
    pred = messagePredicate[m];
    (
    With[{stack = If[TrueQ@OptionValue["CheckQuietedMessages"], _, quietStack[]]},
        handler[Hold[mess:Message[mn_?pred,___], True]] := Throw[$Failed,flag];
        handler[Hold[mess:Message[mn_?pred,___], False]] /; quietedMessageCheck[HoldForm[mn],stack] := Throw[
            Hold[mess],
            flag
        ]
    ];

    Catch[
        Internal`HandlerBlock[{"Message", handler}, body],
        flag,
        (ReleaseHold[#];return)&
    ]
    ) /; pred=!=$Failed
]

SetAttributes[{messagePredicate, messageRules}, HoldAll]
messagePredicate[m_] := Replace[
    messageRules[m],
    r:Except[$Failed] :> Function[Null,ReplaceAll[HoldForm[#], r], HoldAll]
]

messageRules[MessageName[General, m_]] := HoldForm[MessageName[_,m]] -> True
messageRules[MessageName[t_, m_]] := HoldForm[MessageName[t,m]] -> True

messageRules[m:{__MessageName}] := messageRules /@ Unevaluated[m]

messageRules[m_String] := Replace[
Hold[m] /. $MessageGroups,
		{
		Hold[mn:{__MessageName}] :> messageRules[mn],
		_ :> (Message[CheckReturn::mgre, m]; $Failed)
    }
]

messageRules[m_] := (Message[Message::name, HoldForm[m]]; $Failed)

quietStack[] := Alternatives @@ (Stack/.Internal`QuietStatus[])[[1,All,1]]

quietedMessageCheck[m_HoldForm, stack_] := Count[
    First[MessageList /. Internal`QuietStatus[]] /. m -> True,
    {True, stack}
] > 0
$\endgroup$
9
$\begingroup$

The following works pretty well, at least in Mathematica 10:

  1. On the menu bar, go to Evaluation/Debugger Controls/Show Debugger Tools Window.
  2. On the window that pops up, check the box to "Break at Messages"

It will then stop and display a green box around the code that is outputting an error message.

$\endgroup$
2
  • 1
    $\begingroup$ Actually I was aware of this when asking the question (see the very last paragraph), but I needed a way that doesn't require the front end. It turns out that the method used in the accepted solution is the same the debugger uses. It's good to point out this possibility explicitly though, so +1. $\endgroup$
    – Szabolcs
    Commented Oct 30, 2014 at 18:01
  • $\begingroup$ Same option is directly in the Evaluation->Debugger popup in Mathematica 11.1 (checking or unchecking the described "Dhow Debugger Tools Windows" doesn't open a popup for me) $\endgroup$ Commented Mar 30, 2017 at 14:23
8
$\begingroup$

There were some attempts on that in this discussion. I also have this functionality in my debug function posted here

$\endgroup$
8
  • $\begingroup$ Which one do you recommend for practical use? It should work in an environment with no front end, and I need to generalize it for parallel evaluation. $\endgroup$
    – Szabolcs
    Commented Feb 8, 2012 at 18:27
  • 1
    $\begingroup$ @Szabolcs I did not use ot for parallel, but I was debugging serious staff with debug, like stack traces with depth 30 or 50, digging deep into internal stuff, and it all worked quite well. So, I'd rather extend debug for parallel, because it serves me very well. It also is useful in that it gives you the (sort of a) stack trace. $\endgroup$ Commented Feb 8, 2012 at 18:30
  • $\begingroup$ @belisarius's idea works quite well, I'll take a detailed look at debug (for the future) after I've debugged this thing... $\endgroup$
    – Szabolcs
    Commented Feb 8, 2012 at 18:34
  • $\begingroup$ Your debug function looks very useful. There's one big problem though: it breaks on Quieted messages as well. My code, as well as at least some package functions, uses Quiet at certain positions. $\endgroup$
    – Szabolcs
    Commented Feb 8, 2012 at 18:41
  • $\begingroup$ @Szabolcs I will look into it $\endgroup$ Commented Feb 8, 2012 at 18:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.