How do I identify the source of a "Tag times protected" error?



I have some code that looks like

    a = 1;
    b = {2, 3}
    c = i;,
    {i, 2}

which gives an error:

Set::write: Tag Times in c {2,3} is Protected. >>

In this case, it is quite clear that there is a semicolon missing after b = {2, 3}, which is causing this error. However, sometimes I encounter this in large code blocks spanning several lines, which is very difficult to debug.

How can I automate this semicolon hunting to make debugging easier?


Posted 2012-10-12T19:40:10.587

Reputation: 5 283

23Worth to mention that Tag Times ... is Protected message is in 90% cases the result of a missing semicolon. – Kuba – 2016-02-03T07:02:14.607

3Please, upvote the comment of Kuba! – Rexcirus – 2016-03-01T20:36:31.237

1@Rexcirus I laughed out loud at that (A+) – b3m2a1 – 2018-07-08T04:07:33.220



Here is a function findBadSets that will find any explicitly bad Set/SetDelayed attempts in a given expression. Simply wrap it around a syntactically complete block of code, or follow the block with // findBadSets and the errors are printed one per row, protected symbol followed by complete left-hand side for each bad Set:

(* your example *) // findBadSets

Code for the function:

SetAttributes[findBadSets, HoldFirst]

findBadSets[expr_] :=
    Unevaluated @ expr,
    (Set | SetDelayed)[bad : head_Symbol[___], _]
      /; MemberQ[Attributes@head, Protected] :>
        HoldForm[Row[{head, bad}, Spacer[50]]],
   -1] // Column

See also:


Posted 2012-10-12T19:40:10.587

Reputation: 259 163

1WoW, so useful! – matheorem – 2013-11-15T01:32:18.100

1@matheorem My pleasure. :-) – Mr.Wizard – 2013-11-15T19:03:55.693

1That's certainly a faq. – Kuba – 2016-02-03T06:44:51.807

1@Kuba thanks for tagging. – Mr.Wizard – 2016-02-03T06:54:31.253

This is a perfect example of what we could get from code helping functions. For some time now that WRI talks about the eventual inclusion of code improvement suggestion tools. A typical example given is the suggestion of WL functions that could do exactly what the user is programming with a more complex code. But even simpler things can be included, like the small code of Mr. Wizard, but also, for instance, a warning check of "all" the things listed on our common pitfalls post. Is there a frontend framework missing for this purpose? I would even be willing to participate/$ on a crowdfunding... – P. Fonseca – 2016-02-03T08:46:12.600


One can use Trace for this. I stuck in an extra, different error to show it is omitted in the output. It should also be clear how to trace other error messages.

foo = Trace[
    a = 1/0;
    b = {2, 3} 
    c = i;,
   {i, 2}],
  HoldPattern@Message[Set::write, ___],
  TraceAbove -> True]
(* Power::infty, Set::write errors *)

Mathematica graphics

If you would like a function like Mr.Wizard's to apply to a code block, we can wrap it up like this:

traceSet = Function[code,
   HoldPattern@Message[Set::write, __],
   TraceAbove -> True],

Here is a way to view the list of lists of lists of output, somewhat reminiscent of WReach's traceView. (His function is built on TraceScan, which I could not get to work in the way above. The option TraceAbove -> True seems to be ignored. Is that a bug?)

ov[{e1_HoldForm, rest___}, open_: False] := 
  OpenerView[{e1, Column[ov[#, open] & /@ {rest}, Dividers -> All]}, open];
ov[e_, _] := e


ov[foo, True]

Mathematica graphics

Now you can see the offending code comes from

a = 1/0; b = {2, 3} c = i;

which leads to the actual error, {2, 3} c = i. Note that the error message already informs us that the immediate source is c {2,3}.

If it's a very large chunk of code, you can select the bottom segment of the evaluation chain as follows. The length of the chain is controlled by

Length@First@pos == 5

which can be adjusted to suit:

  e_List /; 
   With[{pos = Position[e, HoldPattern@Message[Set::write, ___]]},
    Length[pos] == 1 && Length@First@pos == 5], Infinity] // 
 Column[#, Dividers -> All] &

Mathematica graphics

One could also apply the OpenerView to each element in the output by adding to the pattern in the second argument of Cases the code :> ov[e, True] to make it a transformation rule.

Michael E2

Posted 2012-10-12T19:40:10.587

Reputation: 190 928


After reading this and this answer, I noticed that the debugger is also useful for identifying the error source in this case. You just need to:

  1. Go to Evaluation and check on Debugger.

  2. Check on Break at Messages and click the Show Stack button (alternatively you can click the button after running the erroneous code) in the newly opened panel.

  3. Run the erroneous code.

  4. Go to the bottom of Stack window (opened by the Show Stack button), click the last button, and the erroneous part of code will be highlighted:

enter image description here

  1. Click on Abort in the panel (in some cases you may need to click for several times) to stop the evaluation, and correct the discovered error.


Posted 2012-10-12T19:40:10.587

Reputation: 44 878


A couple other ideas. One is to print the stack when a message occurs:

        a = 1;
        b = {2, 3}
        c = i;,
        {i, 2}

{2,3} c=1

Set::write: Tag Times in c {2,3} is Protected.

{2,3} c=2

Set::write: Tag Times in c {2,3} is Protected.

{Null, Null}

Another is to just click on the ... to the left of the message, and then click on "Show Stack Trace". You will see the problematic Set expression in the stack trace.

Carl Woll

Posted 2012-10-12T19:40:10.587

Reputation: 112 778

A "meta" question here: How does a problem like this get 14,000 views when adjacent questions get roughly 30 views? – David G. Stork – 2017-07-10T22:18:41.080

2@DavidG.Stork it is 5y old, probably was on Hot across SE, it is high in results for Set::write: Tag Times is Protected query. And we link other questions here. – Kuba – 2017-07-11T06:46:20.817

A great answer. – A little mouse on the pampas – 2020-05-09T03:13:43.660