! LaTeX Error: Option clash for package inputenc is usually explained as “the same package was loaded twice with different options”, and that is not quite right. What latex.ltx actually performs is a subset test: the second \usepackage passes if every option it asks for was already among the options of the first load, and clashes the moment one new name appears. That is why \usepackage[a,b]{X} followed by \usepackage[a]{X} is fine while the reverse order fails. More awkwardly, some packages skip the test entirely, and xcolor is the headline example. This page covers what the rule really is, exactly where \PassOptionsToPackage has to go, why hyperref is loaded near the end, and which package pairs genuinely still refuse to coexist on TeX Live 2024.
The clash is triggered by a new option, not by a different one
A second \usepackage clashes the instant it asks for one option the first load did not have. If what it asks for is a subset of the first load — in any order, fewer of them, or none at all — nothing happens. The reason is in latex.ltx: \@onefilewithoptions@clashchk calls \@if@ptions, whose inner \@if@pti@ns walks the requested options one at a time and looks each up in the recorded list with \in@. One miss is enough to select the second branch, which is \@latex@error{Option clash for …}. Seven combinations were run on TeX Live 2024; the table below is the result, and the rule falls straight out of it.
| first load, then second load | Result, measured on TeX Live 2024 |
|---|---|
[alpha] → [beta] | clash — beta is a name the first load never had |
[alpha] → [alpha] | no clash — repeating the same option does nothing at all |
[alpha] → [] | no clash — the empty set is always a subset, so a bare reload is always safe |
[] → [alpha] | clash — this is the classic case of a class or another package getting there first |
[alpha,beta] → [alpha] | no clash — asking for less is always allowed |
[alpha] → [alpha,beta] | clash — asking for more fails; the fix is to give every option at the first load |
[beta,alpha] → [alpha,beta] | no clash — order is irrelevant; the comparison is between sets |
The error line itself is terse, but the .log spells out which options the package was first loaded with and which have just been requested. Those four lines are the whole of the diagnosis, so open the log rather than squinting at the terminal. One more thing worth knowing is that the reported line number is off. Because \usepackage accepts an optional date argument at the end, it has to peek past the closing brace for a [, and that look-ahead reaches into the next line. That is why a clash caused by a \usepackage on line 3 is reported as l.4 \begin{document}.
% terminal shows only the first line; the rest is in the .log
./oc1.tex:4: LaTeX Error: Option clash for package inputenc.
l.4 \begin
{document}
The package inputenc has already been loaded with options:
[utf8]
There has now been an attempt to load it with options
[latin1]
Adding the global options:
utf8,latin1
to your \documentclass declaration may fix this.Why xcolor never clashes: three ways of bypassing the test
Writing \usepackage[dvipsnames]{xcolor} and then \usepackage[table]{xcolor} produces no error at all on TeX Live 2024 — not because xcolor is unusually forgiving, but because the subset test is never called. For an already-loaded package, \@onefilewithoptions in latex.ltx first checks whether a macro named opt@handler@<package>.sty exists. If it does not, control goes to \@onefilewithoptions@clashchk, the subset test above. If it does, the kernel hands the whole thing over, letting that handler process the newly requested options. And xcolor.sty on TeX Live 2024 has moved to the modern scheme: it declares its options with \DeclareKeys and processes them with \ProcessKeyOptions, and \ProcessKeyOptions is precisely what registers opt@[email protected]. Inspecting it with \show returns a one-line body: \ProcessKeyOptions [xcolor].
% no error on TeX Live 2024: xcolor uses \DeclareKeys + \ProcessKeyOptions
\usepackage[dvipsnames]{xcolor}
\usepackage[table]{xcolor}
% still an error: inputenc uses the classic \DeclareOption mechanism
\usepackage[utf8]{inputenc}
\usepackage[latin1]{inputenc}
% check for yourself which mechanism a package uses
\makeatletter
\expandafter\show\csname opt@[email protected]\endcsname
% -> \opt@[email protected]=\protected\long macro: ->\ProcessKeyOptions [xcolor].
\makeatotherMoving to key-value options is the best-behaved bypass, but there are two others. fontenc.sty ends its own file by resetting both [email protected] and [email protected] to \relax — and since \@ifl@aded decides by looking at ver@…, fontenc erases the very fact that it was ever loaded, so the next \usepackage[T2A]{fontenc} counts as a first load. The other is caption, which inside caption3.sty replaces the kernel's \@onefilewithoptions outright: when a caption-family package is loaded again, the new options are routed through the equivalent of \captionsetup and the package is then reloaded with an empty option list. The author's comment just above that code says he asked the LaTeX team for a proper interface in 2018 and again in 2020 and was declined, and he calls his replacement a “dirty hack”. Behind a package that quietly refuses to clash, one of these three is usually at work.
| Package, reloaded with a new option | Result on TeX Live 2024, and why |
|---|---|
xcolor | no clash: it uses \DeclareKeys and \ProcessKeyOptions, so the test is bypassed |
fontenc | no clash: it clears [email protected] at the end of its own load, so it looks unloaded again |
caption | no clash: caption3.sty replaces the kernel's \@onefilewithoptions |
inputenc | clashes: it still uses the classic \DeclareOption mechanism |
geometry | clashes: to add settings later, use \geometry{…} instead of loading it again |
hyperref | clashes: to add settings later, use \hypersetup{…} instead of loading it again |
babel | clashes: list every language in a single \usepackage rather than loading it twice |
amsmath | clashes: options such as fleqn and leqno are conventionally given to the class instead |
Where \PassOptionsToPackage has to go: before the first load, and nowhere else
\PassOptionsToPackage{opt}{X} only means anything if it comes before X is first loaded, and the reliable spot is the first line of the file, above \documentclass. All the command does is append opt to the option list [email protected] — and that single act buys both effects at once: opt is handed to X at the moment it loads, and any later \usepackage[opt]{X} now passes the subset test. Making the option take effect and making the clash disappear are not two separate fixes; they are two faces of the same line. It may sit above \documentclass because \PassOptionsToPackage is defined at format level and, unlike \usepackage, does not assume a class has been read.
% correct: the very first line, above \documentclass
\PassOptionsToPackage{table}{xcolor}
\documentclass{article}
\usepackage{tikz} % pulls xcolor in -- with table already attached
\usepackage[table]{xcolor} % no clash, and \rowcolor works
% WRONG: after xcolor is already loaded. No error is raised, and the
% option is silently never executed.
\documentclass{article}
\usepackage{tikz}
\PassOptionsToPackage{table}{xcolor}
\usepackage[table]{xcolor}The command has a very quiet way of failing. Put \PassOptionsToPackage after X has already been loaded and no error is raised at all — but the option is never executed. Measured with an instrumented test package: placed before the load, the option's code demonstrably runs; placed after it, the clash disappears and the code stays unexecuted. Believing the problem is fixed because the error went away is the most dangerous way to use this tool. There is a second trap in the error text itself, which suggests adding the options globally to \documentclass. That does not work as written: adding \documentclass[beta]{article} while keeping \usepackage[alpha]{X} and \usepackage[beta]{X} reproduces the clash exactly as before. Only removing both local option lists — \documentclass[alpha,beta]{article} with two bare \usepackage{X} — actually gets through.
Finding out what loaded the package you never asked for
Add one \listfiles to the preamble and the end of the .log lists every file that actually loaded; who pulled each one in is answered by the nesting of parentheses in the log. A ( opens a file and ) closes it, so if the ( that opens xcolor.sty sits inside the parentheses of pgfcore.sty, then pgf is what dragged it in. Measured: a bare article reads 3 files, adding one line of tikz takes it to 34, and xcolor is among them; hyperref on its own brings 30. “I never wrote xcolor and I am getting an option clash” is almost always answered by that list. For a finer trail, -recorder writes every opened file into a .fls.
% the nesting says who pulled xcolor in: pgf did
(.../pgf/basiclayer/pgfcore.sty
(.../pgf/systemlayer/pgfsys.sty
...
)) (.../xcolor/xcolor.sty
...
)
% and with \listfiles, the summary table at the end of the .log
*File List*
article.cls 2023/05/17 v1.4n Standard LaTeX document class
xcolor.sty 2022/06/12 v2.14 LaTeX color extensions (UK)
***********Load order: why hyperref goes near the end, and what goes after it
hyperref goes near the end because it overwrites a great many mechanisms — \ref, \cite, \caption, the table of contents, the index — and an overwrite has to be applied to the final definition. If something later redefines the same thing, hyperref's work is simply wiped out. But the rule is “near the end”, not “last”. Packages built on top of what hyperref does must obviously come after it: bookmark, cleveref, hypcap and glossaries are the usual ones. cleveref in particular detects the violation itself and raises an error, so getting it wrong is immediately visible; its exact ordering requirements are covered on the undefined-references page.
One thing deserves to be said plainly. Much of the folklore of the form “A must come before B” produces no effect whatsoever on TeX Live 2024. Trying float with hyperref, geometry with hyperref, algorithm with hyperref, bookmark with hyperref and glossaries with hyperref in both orders produced neither an error nor a warning in any case; packages have accumulated compatibility code for years. So the ordering rules worth obeying are the ones stated in a package's own manual, and rearranging a preamble to satisfy an ordering claim of unknown provenance is usually wasted time. The habit of putting hyperref near the end is worth keeping all the same, because it follows from what overwriting means rather than from folklore.
The difference between \usepackage and \RequirePackage
Inside the preamble the two are literally the same thing: while processing \documentclass, latex.ltx executes \let\usepackage\RequirePackage, so from that point on they are one command. The difference exists only before \documentclass, and inside .sty and .cls files. In those places \usepackage stops with ! LaTeX Error: \usepackage before \documentclass. — the format-level \usepackage is defined purely to produce that diagnostic. That is why a package or class you write yourself uses \RequirePackage, and why the combination with \PassOptionsToPackage lets you inject an option above \documentclass. When a class wants to hand its own options straight down to a package it loads, \RequirePackageWithOptions exists for exactly that.
% before \documentclass, only \RequirePackage works
\RequirePackage{fix-cm}
\PassOptionsToPackage{table}{xcolor}
\documentclass{article}
% inside your own mystyle.sty, likewise
\ProvidesPackage{mystyle}[2026/01/01 house style]
\RequirePackage{xcolor}
\RequirePackageWithOptions{geometry} % forward this package's own optionsPairs that genuinely still refuse to coexist, checked on TeX Live 2024
Beyond options, some pairs cannot coexist because they define the same machinery twice over. There are fewer of them than the folklore suggests, and the symptom is not always an error at load time. The one that refuses outright is biblatex with natbib, which stops at ! Package biblatex Error: Incompatible package 'natbib'. — and if all you wanted was \citet and \citep, \usepackage[natbib=true]{biblatex} gives you those. The awkward case is the pair that breaks quietly: loading both subfigure and subcaption raises no error at all. The trouble surfaces much later, as ! Missing number, treated as zero. on the line where you wrote \begin{subfigure}{0.4\textwidth}, because \begin{subfigure} is swallowed by the old \subfigure command that subfigure defines and is read as something else entirely.
| Pair | What actually happens on TeX Live 2024 |
|---|---|
biblatex + natbib | stops with an error at once; collapse both into \usepackage[natbib=true]{biblatex} |
natbib + biblatex | in this order there is no error, only warnings that \citeauthor and friends are being redefined |
subfigure + subcaption | both load without a murmur; later \begin{subfigure} breaks and reports unrelated-looking errors |
subfig + subcaption | both load, but subcaption declines to define its environment, giving ! LaTeX Error: Environment subfigure undefined. |
caption + subfigure | no longer a clash; the .log merely records Package caption Info: subfigure package is loaded. |
cleveref + hyperref | loading cleveref first stops the run; it has to come after both hyperref and varioref |
cite + natbib | no error, but natbib warns that cite should not be used alongside it; keep only one |
The lesson to draw from that list is to stop trusting “A and B are incompatible” on hearsay and build a five-line document to check. The caption-with-subfigure incompatibility really was an error once; today it has been demoted to an Info. In the other direction, subfigure with subcaption is the clearest case where “it loaded without an error, so we are fine” is the dangerous conclusion. The symptom has shifted from an error at load time to an error much later that looks unrelated — that is where package incompatibility stands on TeX Live 2024, and it is exactly why the habit of running \listfiles and reading the .log pays off.