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

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

See also:

  • Why I get the "Set::write: "Tag Times in is Protected." error?

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[
  Table[
    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,
  Trace[
   code,
   HoldPattern@Message[Set::write, __],
   TraceAbove -> True],
  HoldAll]

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?)

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

Example:

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:

Cases[foo, 
  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.


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.