When you use \renewcommand within another macro or environment, one needs to double up the ## to access the parameters of the inner macro. This serves as a way to distinguish the inner macros ##1 with the outer macros #1 (even if the outer macro does not have any parameters, it provides for error checking). For example:


The references below provide more details on this.


It appears that the same doubling up of the # is needed within a \foreach loop as illustrated in the MWE below.

This took me quite some time to figure this out as the error message that the MWE below gives is:

Illegal parameter number in definition of \pgffor@body

This was within a very deeply nesting of \foreach loops, so I was sure the problem was that I was nesting the \foreach too deeply. Surprisingly, if you skip past the error, the output is still correct, so this made it even harder to locate the problem.


  • Since the \foreach does not have parameters like #1 (as \newcommand does), why is it necessary to double up the # within a definition within a \foreach?
  • How is that the output is still correct, if you simply ignore the error and hit return to continue processing?





\foreach \x in \MyList {%
    \renewcommand*{\SomeCommand}[1]{\color{red}#1}%  Using ## here eliminates the error.
  • 4
    Actually you don't need to use ##1 "to access the parameters of the inner macro" it is simply that you need to use ## to enter #. Sep 15, 2012 at 8:35
  • @DavidCarlisle: Interesting way to look at it. Never thought if # as escaping the #. But, then how do you explain that you need 4 for the next level? :-) Sep 15, 2012 at 9:20
  • I'll add some notes to the answer, code formatting in comments is rubbish Sep 15, 2012 at 9:38
  • Related Question: How to insert a # via \immediate\write18 within a macro. May 18, 2015 at 22:50

1 Answer 1


Internally the definition of foreach will be saving the body of the loop in a macro so it is like (if looping over a,b,... )

\renewcommand*{\SomeCommand}[1]{\color{red}#1}%  Using ## here eliminates the error.

That initial \def (or \newcommand if you prefer) will require a # in the body to be entered as ##. As shown above you would get an error on #1 as \body doesn't take parameters it would have to be entered, as you found, as ##1.

It is possible to define loops in such a way not to require this (for example it could use a token register rather than a macro for saving the body) but that is apparently not the case here.

Note that the need to double # is unrelated to the fact that there is an inner macro definition. It is not that inner macros require ##1 to refer to the first parameter, it is simply that the inner macro definition requires the two tokens # and 1 to refer to the first parameter and to get a # into a macro body you need ##. To see this consider a definition that doesn't have ##1.

You can go


and \hash will be let to # but you can not define a macro as


as that generates

! Illegal parameter number in definition of \definehash.

You need ## to refer to a literal # in a macro definition. So it needs to be


You ask in comments why it needs four # for a double nested definition. Again it is nothing special about the inner definitions, they never "see" ##1 by the time they are evaluated they just see a single #. If you tried to define


The definition would proceed without error but then if you try to execute \ddefinehash you find that it just has a single # in its definition and so you get the error as before:

! Illegal parameter number in definition of \definehash.
<to be read again> 
l.12 \ddefinehash

So you need to get two # into the definition of \definehash and each of those has to be entered as ## so you end up with


Putting it all together:






> \ddefinehash=macro:
->\def \definehash {\let \hash =####}.
l.15 \show\ddefinehash

> \definehash=macro:
->\let \hash =##.
l.16 \show\definehash

> \hash=macro parameter character #.
l.17 \show\hash

No pages of output.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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