Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LaTeX ‘Loading a class or package in a group’ error triggered in unrelated situations? #1626

Closed
dbitouze opened this issue Jan 17, 2025 · 9 comments

Comments

@dbitouze
Copy link
Contributor

Brief outline of the enhancement

If begin{tcolorbox} from the tcolorbox package (I know, it's a third-party package, but the following problem may still be worth mentioning) is added, not explicitly at the beginning of the document, but through \AddToHook{env/document/begin}, compilation fails with the following error:

! LaTeX error: Loading a class or package in a group.

when neither the class nor any package seems to be loaded in a group.

Perhaps something is wrong with the way a class or a package loaded in a group is detected.

Minimal example showing the current behaviour

% \RequirePackage{latexbug}       % <--should be always the first line (see CONTRIBUTING)!
\documentclass{article}
\usepackage{tcolorbox}
\AddToHook{env/document/begin}{\begin{tcolorbox}} % I know, this is a misuse of the `env/document/begin` hook
\AddToHook{env/document/end  }{  \end{tcolorbox}}
\begin{document}
Foo
\end{document}
@muzimuzhi
Copy link
Contributor

The error was raised when loading epstopdf-base package at begindocument hook.

tcolorbox loads tikz, which loads graphics, which then loads epstopdf-base package in its pdftex driver at begindocument.

A simpler example which reproduces the same error:

\RequirePackage{latexbug}       % <--should be always the first line (see CONTRIBUTING)!
\documentclass{article}
\usepackage{graphics}

\AddToHook{env/document/begin}{\begingroup} % I know, this is a misuse of the `env/document/begin` hook
\AddToHook{env/document/end}{\endgroup}
\begin{document}
Foo
\end{document}

log

! LaTeX Error: Loading a class or package in a group.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              
                                                  
l.7 \begin{document}
                    
Classes and packages should only be loaded at the top level


(/path/to/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty
Package: epstopdf-base 2020-01-24 v2.11 Base part for package epstopdf
Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 485.

So the error is detected correctly, just with a vague error message.

@u-fischer
Copy link
Member

You are definitively using the wrong hook. This hook is executed at a time when packages can (and are) still be loaded (e.g. in the following hooks), so you should not put code there that opens a group.

@FrankMittelbach
Copy link
Member

It sure is the wrong hook, but I don't understand what you are attempting to do there with a tcolorbox, what do you intend the tcolorbox to contain?

Right now as written you put the initialization code of \begin{document} inside the tcolorbox and that shouldn't contain any typeset material (as we are still before the start of the actual document where packages are loaded and settings are made and therefore grouping is not allowed (and \begin{tcolorbox} opens a group), so what was the intended outcome (putting the whole document into a tcolorbox perhaps)?

By the way, if you already know that what you do is wrong (as your comment indicates) then opening a bug report here isn't really the right thing to do. Better put such questions in front of the TeX community, e.g. on StackExchange.

@dbitouze
Copy link
Contributor Author

It sure is the wrong hook, but I don't understand what you are attempting to do there with a tcolorbox, what do you intend the tcolorbox to contain?

Well, some silly things 😉: in a class of mine based on the standalone class, I intended to automatically insert a \begin{tcolorbox} just after \begin{document} and a \end{tcolorbox} just before \end{document} in order to get an “infinite” page. Relying on the more appropriate begindocument/end didn't work with the standalone class. Finally, I succeeded with:

\AddToHook{cmd/sa@cls@afterbegindocument/after}{
  \begin{tcolorbox}
}

Right now as written you put the initialization code of \begin{document} inside the tcolorbox

That's not how I understood:

env/⟨env⟩/begin This hook is executed as part of \begin directly in front of the code
specific to the environment start (e.g., the third argument of \NewDocumentEnvironment
and the second argument of \newenvironment).

For me:

\newenvironment{⟨env⟩}{%
  \begin{tcolorbox}
}{
  ...
}

puts the tcolorbox inside the ⟨env⟩, not the other way round.

and that shouldn't contain any typeset material (as we are still before the start of the actual document where packages are loaded and settings are made and therefore grouping is not allowed (and \begin{tcolorbox} opens a group), so what was the intended outcome (putting the whole document into a tcolorbox perhaps)?

Indeed.

By the way, if you already know that what you do is wrong (as your comment indicates) then opening a bug report here isn't really the right thing to do. Better put such questions in front of the TeX community, e.g. on StackExchange.

That's what I did at first, but then I changed my mind because, although it was a misuse, I had the impression that the error that was triggering was causing an inappropriate message and that, perhaps, it was some kind of bug.

@muzimuzhi
Copy link
Contributor

@dbitouze Your understanding may not be wrong, just the document environment is special.

Roughly speaking, \begin{⟨env⟩} executes general hooks like this:

\UseHook{env/⟨env⟩/before}
\begingroup % if ⟨env⟩ is not "document"
  \UseHook{env/⟨env⟩/begin}
  \⟨env⟩

The general hook env/⟨env⟩/begin is used before \⟨env⟩. This is, in my understanding, what its documentation wants to convey

env/⟨env⟩/begin This hook is executed as part of \begin directly in front of the code
specific to the environment start

But for the document environment, some "initialization code of \begin{document}" is stored in \document, including but not limited to the use of one-time hook begindocument. That's why Frank commented with

you put the initialization code of \begin{document} inside the tcolorbox

@FrankMittelbach
Copy link
Member

Well, some silly things 😉: in a class of mine based on the standalone class, I intended to automatically insert a \begin{tcolorbox} just after \begin{document} and a \end{tcolorbox} just before \end{document} in order to get an “infinite” page. Relying on the more appropriate begindocument/end didn't work with the standalone class.

so basically, the standalone class kills the standard hooks in the document environment, because begindocument/end would have been the right hook to use.

I guess standalone should not patch but use begindocument/end and enddocument hooks to inject \standalone and \ifhmode\unskip\fi\endstandalonethese days.

Finally, I succeeded with:

\AddToHook{cmd/sa@cls@afterbegindocument/after}{
\begin{tcolorbox}
}

yes that would work (sort of patch on top of patch). But as I said standalone shouldn't make that patch and if so you could have then simply said

\AddToHook{begindocument/end}{\begin{tcolorbox}[breakable]}

if necessary with a hook rule if the order is not right (but if used in the preamble it would be).

Right now as written you put the initialization code of \begin{document} inside the tcolorbox

That's not how I understood:

env/⟨env⟩/begin This hook is executed as part of \begin directly in front of the code
specific to the environment start (e.g., the third argument of \NewDocumentEnvironment
and the second argument of \newenvironment).

For me:

\newenvironment{⟨env⟩}{%
\begin{tcolorbox}
}{
...
}

puts the tcolorbox inside the ⟨env⟩, not the other way round.

No, it does not put it "inside" ⟨env⟩ (which would also be wrong if you think about it), it puts it directly in front of the code as stated, i.e., before \document in that case.
Thus you end up with \begin{tcolorbox} \document

The only difference between env/.../before and env/.../begin is that the latter happens after \begin opened its group but both are before the code of the environment is executed.

and that shouldn't contain any typeset material (as we are still before the start of the actual document where packages are loaded and settings are made and therefore grouping is not allowed (and \begin{tcolorbox} opens a group), so what was the intended outcome (putting the whole document into a tcolorbox perhaps)?

Indeed.

yes I missread the second part of your hook code, mea culpa

By the way, if you already know that what you do is wrong (as your comment indicates) then opening a bug report here isn't really the right thing to do. Better put such questions in front of the TeX community, e.g. on StackExchange.

That's what I did at first, but then I changed my mind because, although it was a misuse, I had the impression that the error that was triggering was causing an inappropriate message and that, perhaps, it was some kind of bug.

yeah ok, I see how it came about, but it hasn't been a bug: \begin{tcolorbox} does open a group, so anything that \documentdoes is inside a group and inside \document loading of last minute packages does happen.

The correct way to use the hooks in cat case would have been

\documentclass{article}

\usepackage{kantlipsum,tcolorbox}

\tcbuselibrary{breakable,skins}

\AddToHook{begindocument/end}{\begin{tcolorbox}[breakable]}
\AddToHook{enddocument}{\end{tcolorbox}}

\begin{document}

\kant

\end{document}

but as you found that doesn't quite work with the standalone class (but perhaps they should seriously consider using the hooks and not patching \document.

@dbitouze
Copy link
Contributor Author

Many thanks for this detailed comment!

and that shouldn't contain any typeset material (as we are still before the start of the actual document where packages are loaded and settings are made and therefore grouping is not allowed (and \begin{tcolorbox} opens a group)

BTW, would using \tcolorbox...\endtcolorbox instead of \begin{tcolorbox}...\end{tcolorbox} have made any difference in terms of group?

yes I missread the second part of your hook code, mea culpa

You are very welcome!

but as you found that doesn't quite work with the standalone class (but perhaps they should seriously consider using the hooks and not patching \document.

I just suggested this on the repository of standalone.

@FrankMittelbach
Copy link
Member

Many thanks for this detailed comment!

and that shouldn't contain any typeset material (as we are still before the start of the actual document where packages are loaded and settings are made and therefore grouping is not allowed (and \begin{tcolorbox} opens a group)

BTW, would using \tcolorbox...\endtcolorbox instead of \begin{tcolorbox}...\end{tcolorbox} have made any difference in terms of group?

it might be but I doubt it. tcolorbox has to wrap everything in a box (which is a group of its own(. Anyway, it would still be wrongm as you start typesetting before \document has finished. So don't experiment with that.

but as you found that doesn't quite work with the standalone class (but perhaps they should seriously consider using the hooks and not patching \document.

I just suggested this on the repository of standalone.

good. It is actually more than a recommendation really, because standalone breaks the documented interfaces of LaTeX, e.g. begindocument/end hook is documented as being at the very end of \document only followed by \ignorespaces which is no longer true once they added the current patch.

@dbitouze
Copy link
Contributor Author

dbitouze commented Jan 19, 2025

It is actually more than a recommendation really, because standalone breaks the documented interfaces of LaTeX

BTW, the comments of this answer on TeX.SE are:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants