How can I pass underscore to \newcommand properly? suggests the solution is to use a zero-argument command that changes the catcode of _, before expanding to the actual command.

That's kind of the opposite of why I'd want to use \NewDocumentCommand, as it's kind of awkward, and also obfuscating argument types.

Is there a way to pass strings containing underscores (file names, by the way) without leaving the comfort of my expl3/xparse/\NewDocumentCommand bubble?

I don't want to use v arguments; it should really function like a normal macro, \includechapter{foo_bar} and not like \includechapter!foo_bar!.

My code currently:

%%% Chapter Inclusion Macros
% Command to include chapter files, if
% either the exclusive chapter list is empty,
% or said chapter is in there
\cs_set:Npn \cel_includechapter:n #1 {
  % Check whether list is empty
  \g_cel_enabled_clist % which list
  {\include{#1/#1}} % if empty, just include
  { % else
    % check whether argument in list of enabled chapters
    \g_cel_enabled_clist % in which list
    {#1} % which element to look for
    {\include{#1/#1}} % if in there
    {\chapter{#1~(currently~disabled)}} %if not in there
% user-facing command \includechapter
% includes chaptername/chaptername
% if enabled
  \clist_put_right:Nn \g_cel_enabled_clist {#1}

The build breaks when reaching



! Missing $ inserted.
<inserted text>
l.147 \includechapter{foo_bar}
  • Use v-type argument or detokenize. (each has its disadvantage, learn TeX for more details)
    – user202729
    May 6, 2022 at 14:31
  • Actually... if egreg answer this, consider answering the other question then close this one as duplicate of that instead. Avoid scattering answers everywhere.
    – user202729
    May 6, 2022 at 14:32
  • Turns out there's already a comment under that answer you link to for an... alternative approach. Check out if you want.
    – user202729
    May 6, 2022 at 14:34
  • 1
    If it's about the interface, v-type in xparse (unlike \verb command) can use {...} too.
    – user202729
    May 6, 2022 at 14:42
  • 1
    @user202729 My apologies, yes, you're right. Going to try it out! May 6, 2022 at 14:46

2 Answers 2


The problem is where you say

{\chapter{#1~(currently~disabled)}} %if not in there

because an underscore in the file name would trigger math mode.

Solution: change into

{\chapter{\tl_to_str:n {#1}~(currently~disabled)}} %if not in there

The solution in this case is to use v-type arguments:

  \clist_put_right:Nn \g_cel_enabled_clist {#1}

This still requires more fixing, since the argument passed through needs to get processed before it can be typeset if it contains underscores.

Luckily, I don't want to use this macro as argument to another function (usrguide3.pdf):

v: Reads an argument ‘verbatim’, between the following character and its next occurrence, in a way similar to the argument of the LATEX 2ε command \verb. Thus a v-type argument is read between two identical characters, which cannot be any of %, \, #, {, } or . The verbatim argument can also be enclosed between braces, { and }. A command with a verbatim argument will produce an error when it appears within an argument of another function.

  • By the way the "fixing" can be done with \scantokens if you know how
    – user202729
    May 6, 2022 at 15:00
  • @user202729 I went with \chapter{\protect\detokenize{#1}~(currently~disabled)} May 6, 2022 at 15:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .