[Tex/LaTex] Citation link not split for page break, again

errorshyperrefnatbib

I have stumbled over a rare case of the notorious \pdfendlink ended up in different nesting level than \pdfstartlink error on an up to date system (Ubuntu 14.10, hyperref 6.83m). It occurs if all of the conditions below are met:

  • double column mode
  • when a link spans two pages
  • when there is a figure that spans over two columns on the same page as the start of the link.

Note that, for links that don't span a page but two lines, natbib and hyperref for (Author, Year) style produces two links (correctly). The issue occurs only at page boundary. Also, the issue doesn't occur in single column mode (see modified example). The figure also seems to be necessary (see yet another modified example).

What is a good workaround for this issue during development of a document? (I find it useful to have clickable links, and I also prefer sticking to twocolumn mode for now.) Is a fix for hyperref technically possible?

This can be seen as one of those Questions which are bug reports.
While I'm aware of this, a workaround still might be of use for the limited time it takes for a fix to propagate to, say, Ubuntu LTS (which might be up to four years, an eternity to some). Thus, it might be useful for documentation purposes; please feel free to close if it's not appropriate.

MWE (also on GitHub)

…minimal to me but unfortunately not small, and uses the btxdoc.bib from natbib.

\documentclass[a5paper,twocolumn]{scrartcl}
\pagestyle{empty}
% Fatal combination
\usepackage{natbib,hyperref}

% For constructing the MWE
\usepackage{mwe,lipsum}

\bibliographystyle{chicago}

\begin{document}
  \begin{figure*}[t]
    \includegraphics[width=\textwidth]{example-image-golden}
  \end{figure*}
  \lipsum[1]
  \lipsum[1]
  \lipsum[2]
  Test line break:
  \citep{strunk-and-white}
  Works for first word.
  \citep{strunk-and-white}
  And for second.

  Conclusion: Line breaks work well.

  Now what happens if we force the break at the page boundary?
  Let's take a look

  We make this just long enough to break the link at page boundary
  \citep{strunk-and-white}
  \bibliography{btxdoc}
\end{document}

Error message

! pdfTeX error (ext4): \pdfendlink ended up in different nesting level than \pd
fstartlink.
\AtBegShi@Output ...ipout \box \AtBeginShipoutBox 
                                                  \fi \fi 
l.33 \end{document}

Output

(page 2) of a slightly modified non-breaking example:

Page 2 of output (as desired)

Best Answer

The floating object (figure*) spanning two columns is the culprit here, as it introduces an additional level of boxing of the output page containing the \pdfstartlink which opens the citation hyperlink.

The page that follows is a "normal" two-column page without a float and thus the closing \pdfendlink ends up in a box whose level is one less.

To remedy the situation, we could add one boxing level to the offending \pdfendlink. For this, the example below defines

\addOneNestingLevelEndLink

which is inserted immediately before the offending \citep command.

The opposite situation of a two-column float placed on the page where the citation hyperlink ends is possible too. Here, the boxing level of the \pdfstartlink command must be increased. Therefore,

\addOneNestingLevelStartLink ,

likewise to be put in front of the citation command in question, is provided. Either one or the other of these commands may be used at a time.

Example (on ShareLaTeX):

\documentclass[a5paper,twocolumn]{scrartcl}

\usepackage{filecontents}
\begin{filecontents}{btxdoc.bib}
@BOOK{strunk-and-white,
   author = "Strunk, Jr., William and E. B. White",
   title = "The Elements of Style",
   publisher = "Macmillan",
   edition = "Third",
   year = 1979 }
\end{filecontents}
\pagestyle{empty}

\usepackage{natbib}
\usepackage[colorlinks,citecolor=blue]{hyperref}

% For constructing the MWE
\usepackage{mwe,lipsum}

\bibliographystyle{chicago}

\makeatletter\ifdefined\Hy@StartlinkName
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% \addOneNestingLevelStartLink
% \addOneNestingLevelEndLink
%
% put ONE of \addOneNestingLevel(Start|End)Link in front of offending \cite
% depending on the placement of the double-column float object
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\def\addOneNestingLevelStartLink{%
  \gdef\Hy@StartlinkName##1##2{%
    \sbox0{\Hy@StartlinkNameOrig{##1}{##2}}\usebox0
    \global\let\Hy@StartlinkName\Hy@StartlinkNameOrig%
  }%
}
\def\addOneNestingLevelEndLink{%
  \gdef\pdfendlink{%
    \sbox0{\pdfendlinkOrig}\usebox0%
    \global\let\pdfendlink\pdfendlinkOrig%
  }%
}
\let\Hy@StartlinkNameOrig\Hy@StartlinkName
\let\pdfendlinkOrig\pdfendlink
\else
\let\addOneNestingLevelStartLink\relax
\let\addOneNestingLevelEndLink\relax
\fi
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\makeatother

\begin{document}
  \begin{figure*}[t]
    \includegraphics[width=\textwidth]{example-image-golden}
  \end{figure*}
  \lipsum[1]
  \lipsum[1]
  \lipsum[2]
  Test line break:
  \citep{strunk-and-white}
  Works for first word.
  \citep{strunk-and-white}
  And for second.

  Conclusion: Line breaks work well.

  Now what happens if we force the break at the page boundary?
  Let's take a look

  We make this just long enough to break the link at page boundary
  \addOneNestingLevelEndLink\citep{strunk-and-white}
  \bibliography{btxdoc}
\end{document}
Related Question