Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

BibTeX Linter Rules

badness lint runs a parallel set of built-in rules over each .bib file’s parse tree and reports a diagnostic for every finding. This page is the catalogue: one section per rule, keyed by its stable rule id. Bib rules share one id namespace with the LaTeX rules, so the same [lint] select/ignore (and --select/--ignore) target both.

Every rule is on by default; narrowing happens only through select/ignore in the [lint] table (see the Configuration reference). Where a rewrite is unambiguous a rule carries an auto-fix: a safe fix (shown below as “After applying the fix”) is applied by badness lint --fix.

Each example below is linted live to produce its diagnostic and fixed output, so this page never drifts from the rules’ actual behavior.

duplicate-key

Flag a cite key defined by more than one entry in the same .bib file. Keys are compared case-insensitively, matching BibTeX, which silently keeps only one of the colliding entries; every definition after the first is flagged. No autofix: resolving the collision (rename vs delete) is the author’s call.

The same cite key defined by two entries:

@misc{knuth84, title = {Draft}}
@book{knuth84, title = {Book}}
warning: duplicate-key
 --> references.bib:2:7
  |
2 | @book{knuth84, title = {Book}}
  |       ^^^^^^^ cite key `knuth84` is defined more than once

missing-required-field

Flag a regular entry lacking a field its type requires, per the biblatex data model. An alternation like date or year is satisfied by either, and classic-BibTeX aliases count (journal satisfies journaltitle). An entry type the built-in database does not know carries no signature and is never flagged. Report-only – field content cannot be invented.

An @article without its required journaltitle:

@article{doe2020,
  author = {Doe, Jane},
  title  = {A study},
  year   = 2020
}
warning: missing-required-field
 --> references.bib:1:10
  |
1 | @article{doe2020,
  |          ^^^^^^^ entry `article` is missing required field `journaltitle`

unknown-field

Flag a field that is neither required nor optional for its entry type and carries no global field metadata – usually a typo, or data misplaced from another entry type. BibLaTeX silently ignores fields it does not know, so the mistake otherwise vanishes without a trace. Only entry types the built-in database knows are checked. Report-only – deleting the field would discard data.

A typo’d field name (pubisher for publisher):

@book{turing50,
  author   = {Turing, Alan},
  title    = {A book},
  pubisher = {Elsevier},
  year     = 1950
}
warning: unknown-field
 --> references.bib:4:3
  |
4 |   pubisher = {Elsevier},
  |   ^^^^^^^^ unknown field `pubisher` on `book` entry

empty-field

Flag a field whose value is empty or whitespace-only (title = {}, note = ""). An empty field carries no data, and some styles still emit punctuation around it. The safe autofix deletes the field along with its separating comma.

An empty note left behind by an edit:

@misc{knuth84,
  title = {Draft},
  note  = {}
}
warning: empty-field
 --> references.bib:3:3
  |
3 |   note  = {}
  |   ^^^^^^^^^^ field `note` is empty

After applying the fix:

@misc{knuth84,
  title = {Draft}
}

duplicate-field

Flag a field name appearing more than once on a single entry (names compared case-insensitively). BibTeX and Biber keep only one occurrence and silently discard the rest, so a duplicate is almost always a merge or copy-paste mistake; every occurrence after the first is flagged. When the repeated value is byte-identical to the kept one, a safe autofix deletes the redundant copy; when the values differ, which one wins is engine-dependent, so the finding is report-only.

Two note fields with identical values – deleting the redundant copy is safe:

@misc{knuth84,
  note = {Draft},
  note = {Draft}
}
warning: duplicate-field
 --> references.bib:3:3
  |
3 |   note = {Draft}
  |   ^^^^ duplicate field `note` on `misc` entry

After applying the fix:

@misc{knuth84,
  note = {Draft}
}

Differing values are report-only (which copy the engine keeps is style-dependent, so dropping either would change meaning):

@misc{knuth84,
  note = {First draft},
  note = {Second draft}
}
warning: duplicate-field
 --> references.bib:3:3
  |
3 |   note = {Second draft}
  |   ^^^^ duplicate field `note` on `misc` entry

unused-string

Flag an @string macro defined in the file but never referenced by any field value. For the common self-contained .bib an unused macro is dead weight; in a multi-file bibliography it may be referenced from another .bib, so treat cross-file setups with care – cross-file @string resolution is not modeled yet. Report-only: deleting a definition is a meaning-level edit left to the author.

A defined macro no field value references:

@string{cup = {Cambridge University Press}}
@book{turing50, title = {Draft}, publisher = {Springer}}
warning: unused-string
 --> references.bib:1:9
  |
1 | @string{cup = {Cambridge University Press}}
  |         ^^^ `@string` macro `cup` is defined but never used

undefined-string

Flag an @string macro used in a field value but defined nowhere in the file (the twelve month macros jan..dec are predefined). Usually a typo’d macro name or a missing @string definition; BibTeX errors on it at build time. In a multi-file bibliography the definition may live in another .bib, so a use resolved there is a false positive – cross-file @string resolution is not modeled yet. Report-only: the fix (define the macro or correct the name) is a meaning-level edit left to the author.

A typo’d macro name (cpu for cup):

@string{cup = {Cambridge University Press}}
@book{turing50, title = {Draft}, publisher = cpu}
warning: undefined-string
 --> references.bib:2:46
  |
2 | @book{turing50, title = {Draft}, publisher = cpu}
  |                                              ^^^ `@string` macro `cpu` is used but never defined

title-capitalization

Flag an unprotected acronym or mid-word capital in a title-like field (title, booktitle, journaltitle, …). Many bibliography styles lowercase unprotected title text, so DNA renders as dna unless written {DNA}. Flagged are runs of two or more capitals and the camelCase brand pattern (a first capital mid-way through a lowercase-initial word, like iPhone); ordinary Title Case, name particles (McDonald), and mixed-case tokens (LaTeX) stay quiet, as does anything already inside a {...} group. Report-only – choosing what to protect is the author’s call.

An unprotected acronym a title-lowercasing style would render as dna:

@article{watson53, title = {Molecular structure of DNA}}
warning: title-capitalization
 --> references.bib:1:52
  |
1 | @article{watson53, title = {Molecular structure of DNA}}
  |                                                    ^^^ unprotected capitals `DNA` in `title`; wrap in braces (`{DNA}`) to keep case under title-lowercasing styles

encoding-hints

Surface non-ASCII text in a field value as a hint (accented text is perfectly valid in a UTF-8 setup, hence not a warning). Raw non-ASCII renders correctly only when the file is UTF-8 and the document loads a matching input encoding (inputenc with pdfLaTeX, fontspec with Xe/LuaLaTeX); legacy toolchains may mangle it. Either confirm the encoding or use a LaTeX escape (\'e for é). Report-only – the right fix depends on the project’s toolchain.

An accented name entered as raw UTF-8:

@article{erdos47, author = {Erdős, Paul}}
help: encoding-hints
 --> references.bib:1:32
  |
1 | @article{erdos47, author = {Erdős, Paul}}
  |                                ^ non-ASCII text `ő`; ensure the file is UTF-8 and the document loads an input encoding (inputenc/fontspec), or use a LaTeX escape

Suppression

BibTeX has no line-comment token, so per-site suppression rides a structured @comment entry instead of the LaTeX % directive. A plain directive suppresses one rule on the next entry:

@comment{badness-ignore missing-required-field: publisher long gone}
@book{oldbook, title = {An Orphaned Book}}

@comment{badness-ignore-file <id>: ...} suppresses one rule file-wide, and @comment{badness-ignore-file: ...} suppresses all rules file-wide. Parse diagnostics (rule id parse) are never suppressed.