The code below outputs:

ERROR: Package Foo Error: Unknown key, \l_keys_key_tl

Why does \l_keys_key_tl expand at Hook 1, not Hook 2?




  \keys_define:nn { \__erw_foo_options }
    key .value_required:n = true,

    unknown .code:n =
      { Unknown~key,~\l_keys_key_tl}  % Hook 1

      { Foo }
      { generic }
      { Unknown~key,~\l_keys_key_tl} % Hook 2

   \keys_set:nn { \__erw_foo_options } {#1}







  • 1
    IIRC, the error message for unknown keys comes for free with l3keys. There should be no need to explicitly handle this situation.
    – frougon
    Commented Mar 5, 2020 at 19:57

1 Answer 1


The expansion behaviour of \msg_error:nnn, etc., is tightly defined: they pass the third (fourth, etc.) arguments unchanged. As such, you want to expand the variable using \msg_error:nnx. In contrast, just 'dumping the text' will convert the tl to its expansion at point-of-typesetting: this is the documented behaviour of token lists.

  • 1
    Also, \keys_define:nn { \__erw_foo_options } uses \__erw_foo_options literally as the family for keys: you almost certainly mean something like \keys_define:nn { erw } ....
    – Joseph Wright
    Commented Mar 5, 2020 at 17:56
  • Thanks for the explanation! Is the non-expanding behavior of \msg_new:nnn something that has changed in the last 3 years or so? Because I have code where I used \exp_not:n in the third argument of \msg_new:nnn, as if it were handled by \message... but this would appear to be unnecessary. Remark: \l_keys_key_tl appears to work, but my interface3.pdf doesn't document it (it documents \l_keys_key_str, which also works).
    – frougon
    Commented Mar 5, 2020 at 18:07
  • @JosephWright I guess you meant \keys_define:nn { __erw_foo_options } (a name, not a token)?
    – Erwann
    Commented Mar 5, 2020 at 18:13
  • @JosephWright Ah, I see in the .dtx: “\begin{variable}{\l_keys_key_str, \l_keys_key_tl} The |tl| version is deprecated but has to be handled manually.”. @Erwann I'm not Joseph, but I'd say “no”. The first argument of \keys_define:nn is usually the package name (and erw is three tokens).
    – frougon
    Commented Mar 5, 2020 at 18:15
  • @frougon. OK, I get it.
    – Erwann
    Commented Mar 5, 2020 at 18:20

You must log in to answer this question.

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