28
$\begingroup$

If I evaluate this expression:

Module[{}, 1/0;0^0]; msg = $MessageList

I get:

"Power::infy: Infinite expression 1/0 encountered. >>"
"Power::indet: Indeterminate expression 0^0 encountered. >>"
{Power::infy,mrtError::function}

How can I collect the complete error messages in msg, instead of just the first part? Something for msg like:

{"Power::infy: Infinite expression 1/0 encountered. >>"
,"Power::indet: Indeterminate expression 0^0 encountered. >>"}

Some clue?

$\endgroup$
0

5 Answers 5

22
$\begingroup$

Update See here for a documented way to do the very same thing in v10.0 or later.


This method will only catch those messages which would actually get printed, not those which are Quieted or turned Off.

We can use handlers:

messages = {}
clearMessages[] := messages = {}
collectMessages[m_] := AppendTo[messages, m]
Internal`AddHandler["Message", collectMessages]

Then do

clearMessages[]
1/0; 0/0;
messages

Mathematica graphics

Internal`RemoveHandler["Message", collectMessages]

Reference and details: How to abort on any message generated?

$\endgroup$
5
  • $\begingroup$ I really do worry about my failing brain. I was about to ask where you learned this but I've already voted on your answer in the referenced thread. Anyway a semi-senile +1. $\endgroup$
    – Mr.Wizard
    Commented Feb 27, 2013 at 15:36
  • $\begingroup$ @Mr.Wizard you've voted ~4500 times, answered nearly 900 questions, and asked over 50 yourself. Sure, senility is the reason you can't remember what you've done before on this site. Absolutely. :) $\endgroup$
    – rcollyer
    Commented Feb 27, 2013 at 15:44
  • $\begingroup$ @rcollyer I keep telling myself that but it pervades other facets of life I'm afraid. $\endgroup$
    – Mr.Wizard
    Commented Feb 27, 2013 at 15:53
  • 1
    $\begingroup$ @Mr.Wizard I think I'm younger than you, but I already suffer from CRS (can't remember "stuff"), and have for most of my life. So, I wouldn't worry about it. Besides, you'll forget about it in a couple of minutes anyway. :) $\endgroup$
    – rcollyer
    Commented Feb 27, 2013 at 15:58
  • 1
    $\begingroup$ @rcollyer I changed my avatar to something more appropriate. (The thing is I'm not old, I just feel like it.) $\endgroup$
    – Mr.Wizard
    Commented Feb 27, 2013 at 16:03
23
$\begingroup$

In version 10 or later, we can use EvaluationData.

EvaluationData[1/0; 0^0]

Mathematica graphics

Behind the scenes, this uses handlers, like in my first answer, meaning that only those messages will be recorded which would get printed.

$\endgroup$
2
  • 1
    $\begingroup$ Holy cow this is something I had no idea even existed. $\endgroup$
    – Pillsy
    Commented Oct 31, 2018 at 14:14
  • 2
    $\begingroup$ @Pillsy It's new in v10.0, and it has not been advertised much. Those of us who started much earlier and were used to different ways of doing things would easily miss it. $\endgroup$
    – Szabolcs
    Commented Oct 31, 2018 at 17:44
10
$\begingroup$

Simply you could use $MessagePrePrint to get the "fillers" and $MessageList as you did to get the message name they belong to:

$MessagePrePrint = Sow;

Reap[
 Module[{}, 1/0; 0^0]; $MessageList
]
{{Power::infy,Power::indet},{{1/0,0^0}}}

For complete control you could go low-level and intercept MessagePacket as I did for:
Prepend Information to Warning Messages

$\endgroup$
5
  • $\begingroup$ Or, just capture the info from Message directly. $\endgroup$
    – rcollyer
    Commented Feb 27, 2013 at 15:31
  • $\begingroup$ @rcollyer okay, I agree that's better here. $\endgroup$
    – Mr.Wizard
    Commented Feb 27, 2013 at 15:35
  • $\begingroup$ Given your new avatar, I'm compelled to bring back the Hypnotoad... $\endgroup$
    – rm -rf
    Commented Feb 27, 2013 at 16:12
  • $\begingroup$ @rm-rf -- do as you wish :-) $\endgroup$
    – Mr.Wizard
    Commented Feb 27, 2013 at 16:13
  • 1
    $\begingroup$ @rm-rf that is a very odd toad. $\endgroup$
    – Mr.Wizard
    Commented Feb 27, 2013 at 16:21
9
$\begingroup$

The following method will capture all messages, regardless of whether they are Quieted or turned Off. Messages that are turned off will be wrapped in $Off.

You could always capture the information directly,

myMessageList = {};
Internal`InheritedBlock[{Message, $InMsg = False},
 Unprotect[Message];
 Message[msg_, vars___] /; ! $InMsg :=
  Block[{$InMsg = True},
   AppendTo[myMessageList, {HoldForm[msg], vars}];
   Message[msg, vars]
   ];
 (* code to run *)
 Module[{}, 1/0; 0^0]
 ];
myMessageList

(* {{Power::infy, HoldForm[1/0]}, {Power::indet, HoldForm[0^0]}} *)
$\endgroup$
1
  • $\begingroup$ This is all great, but this code intercepts messages that are hidden deep inside built-in functions. For example, ParametricNDSolve generates dozens of General::newsym messages when it is first called on parallel kernels. You have to block them something like this: If[MemberQ[{HoldForm[General::newsym], HoldForm[FrontEndObject::notavail], HoldForm[ReplaceAll::reps], HoldForm[Unset::norep]}, HoldForm[msg]] , Return[] , AppendTo[msgs, {HoldForm[msg], vars}]; msgCount++; msgTotalCount++; ]; Is there a better way? $\endgroup$ Commented Nov 25, 2022 at 1:21
3
$\begingroup$

You can use Messages[foo] to get the text of any message. With that, we can proceed as follows to extract the text of the messages that were last generated:

Module[{}, 1/0;0^0]; msg = $MessageList; (* last errors *)

With[{messages = ReleaseHold@
    DeleteDuplicates[# /. HoldPattern@MessageName[s_, _] :> Messages@s] &},

    # /. messages@#] &@msg
(* {{Infinite expression `1` encountered.,Indeterminate expression `1` encountered.}} *)

Note that you will not be able to retrieve whatever was inserted in the placeholder `1` with this.

$\endgroup$

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.