# Repeated “Label(s) may have changed” when using \catcode_=12 underscore hack with hyperref

This MWE produces repeated Label(s) may have changed warnings despite the output files not changing. The same problem has been discussed in How to diagnose a permanent "Label(s) may have changed" warning?, but lacking an MWE could only symptomatically be solved (by removing the underscore from the \caption). Now, I do not want to remove the underscore from the caption.

\documentclass{article}
\usepackage{hyperref}
\AtBeginDocument{
\catcode_=12
\begingroup\lccode~=_
\lowercase{\endgroup\let~}\sb
\mathcode_="8000
}
\begin{document}
\begin{figure}
\caption{$x_y$}
\label{z}
\end{figure}
\end{document}


An even more minimal MWE:

\documentclass{article}
\usepackage{hyperref}
\begin{document}
\catcode_=12
\begin{figure}
\caption{$x_y$}
\label{z}
\end{figure}
\end{document}


Some background: I use the

\catcode_=12


hack after the discussion (and egreg's answer) at Underscore in textmode vs mathmode, among other things, to allow use of underscores in DOIs and bibtex keys. But it seems to interfere with hyperref and captions.

What can I do?

• This stems from the fact that you're changing the \catcode within the document environment, and that the .aux is usually read \AtBeginDocument. So, there's no correspondence between the _ read in by the .aux and written out by \caption. – Werner May 19 '15 at 23:11
• Oh. So you mean I can simply move the \catcode before \begin{document} and be done? Seems to work. So what is the \AtBeginDocument{...} for then? Just to prevent the \catcode from interfering with anything else in the preamble? Is there anything such as \BeforeBeginDocument? – bers May 19 '15 at 23:15
• etoolbox provides some environment hooks which you can use (like \BeforeBeginEnvironment{document}{<stuff>} and \AtBeginEnvironment{document}{<stuff>}). – Werner May 19 '15 at 23:20
• Someone else might try that, egreg's answer works for me. Thanks anyway! Just to add that \AfterEndPreamble from etoolbox did not work. – bers May 19 '15 at 23:28

This should solve the issue. The _ will have the right category code when the .aux file is read at begin document. I believe the problem is in the fact that arguments are grabbed “too soon” when hyperref is loaded.

\documentclass{article}
\usepackage{hyperref}

\makeatletter
\AtBeginDocument{
\catcode_=12
\begingroup\lccode~=_
\lowercase{\endgroup\let~}\sb
\mathcode_="8000
\immediate\write\@auxout{\catcode_=12 }
}
\makeatother

\begin{document}
\begin{figure}
\caption{$x_y$}
\label{z}
\end{figure}
\end{document}

• It does! What else can I say? Thanks! – bers May 19 '15 at 23:25

Actually the only thing that seems to be required is in the preamble

\makeatletter
\AtBeginDocument{
\catcode_=12
\begingroup\lccode~=_
\lowercase{\endgroup\let~}\sb
\immediate\write\@auxout{\catcode_=12 }
\catcode^=12
\begingroup\lccode~=^
\lowercase{\endgroup\let~}\sp
\mathcode^="8000
\immediate\write\@auxout{\catcode^=12 }
}
\makeatother
`

Note that I have also experienced problems (less reproducibly) with equations that have superscripts in them. Hence the ^ case as well. I don't know why that seems to need the mathcode reset when the _ case doesn't. Probably one should include it in both.