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. Each section describes
one rule, identified by its stable rule id. BibTeX rules share an id
namespace with the LaTeX rules, so the same [lint] settings
and --select and --ignore flags select both sets.
Most rules are on by default. Each rule’s section states whether it is
enabled by default. Use select to enable an opt-in rule, or use select and
ignore in the [lint] table to narrow the default set. See the
Configuration reference.
Some rules offer an autofix when a rewrite is unambiguous.
badness lint --fix applies safe fixes, shown below under “After applying the
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 citation 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 is offered because the author must choose whether to rename or delete an entry.
This rule is enabled by default.
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
deprecated-suppression-syntax
Flag the retired @comment{badness-ignore <rule>} and @comment{badness-ignore-file [<rule>]} suppression spellings, which remain accepted for compatibility but are no longer documented. The Safe autofix rewrites only the family and verb to badness-lint skip or badness-lint skip-file; the selector, reason, delimiters, and remaining entry text stay byte-for-byte unchanged. This meta diagnostic is not silenced by the retired directive it reports; use [lint].ignore to disable the rule deliberately.
This rule is enabled by default.
A retired suppression directive in a structured comment:
@comment{badness-ignore unused-string: intentional}
@string{x = {X}}
warning: deprecated-suppression-syntax
--> references.bib:1:10
|
1 | @comment{badness-ignore unused-string: intentional}
| ^^^^^^^^^^^^^^ retired suppression syntax; use `@comment{badness-lint skip …}` instead
After applying the fix:
@comment{badness-lint skip unused-string: intentional}
@string{x = {X}}
inert-suppression
Flag a structured BibTeX suppression directive that cannot take effect: skip with no following entry, on with no matching off, or any badness-format directive, because the BibTeX formatter does not support format suppression. Also flag an off region left open at EOF; it currently suppresses through the end of the file, but the missing closer is usually accidental. Report-only: repairing the directive requires knowing the entry, boundary, or formatting policy the author intended. Inline suppressions cannot hide this meta diagnostic; use [lint].ignore to disable the rule deliberately.
This rule is enabled by default.
BibTeX recognizes the directive grammar, but its formatter has no suppression mechanism:
@comment{badness-format skip-file: preserve this file}
@book{key}
warning: inert-suppression
--> references.bib:1:1
|
1 | @comment{badness-format skip-file: preserve this file}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the BibTeX formatter does not support format suppression, so this directive does nothing
missing-required-field
Flag an entry lacking a field its type requires under the biblatex data model. An alternative such as date or year is satisfied by either field, and classic BibTeX aliases count (journal satisfies journaltitle). Entry types unknown to the built-in database have no signature and are not flagged. No autofix is offered because the rule cannot supply the missing content.
This rule is enabled by default.
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 has no global field metadata. Such a field is usually a typo or data intended for another entry type. BibLaTeX silently ignores unknown fields, so the mistake can otherwise go unnoticed. The rule checks only entry types known to the built-in database. No autofix is offered because deleting the field would discard data.
This rule is enabled by default.
A misspelled 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.
This rule is enabled by default.
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 in an entry, comparing names case-insensitively. BibTeX and Biber keep only one occurrence and silently discard the rest. A duplicate is therefore almost always a merge or copy-paste mistake, and every occurrence after the first is flagged.
When a repeated value is byte-identical to the retained value, a safe autofix deletes the redundant copy. When values differ, the retained value depends on the engine, so the rule reports the finding without a fix.
This rule is enabled by default.
Two note fields with identical values, so 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 a field value. In a self-contained .bib file, an unused macro serves no purpose. In a multi-file bibliography, another .bib file may reference it, and cross-file @string resolution is not yet modeled. No autofix is offered because deleting a definition is a choice for the author.
This rule is enabled by default.
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 from jan through dec are predefined. An undefined macro usually means a misspelled name or a missing @string definition, and BibTeX reports an error at build time.
In a multi-file bibliography, another .bib file may supply the definition. Cross-file @string resolution is not yet modeled, so those uses produce false positives. No autofix is offered because the author must choose whether to define the macro or correct its name.
This rule is enabled by default.
A misspelled 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 as {DNA}.
The rule flags runs of two or more capitals and camelCase brand names whose first capital occurs within a word that begins with a lowercase letter, such as iPhone. It leaves ordinary Title Case, name particles (McDonald), mixed-case tokens (LaTeX), and text already inside a {...} group alone. No autofix is offered because the author must choose what to protect.
This rule is enabled by default.
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
Report non-ASCII text in a field value as a hint. Accented text is valid in a UTF-8 setup, so this is not a warning. Raw non-ASCII text renders correctly only when the file is UTF-8 and the document loads a matching input encoding (inputenc with pdfLaTeX, fontspec with XeLaTeX or LuaLaTeX). Legacy toolchains may corrupt it. Confirm the encoding or use a LaTeX escape (\'e for é). No autofix is offered because the right change depends on the project’s toolchain.
This rule is enabled by default.
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 write suppression directives inside
structured @comment entries. A skip directive suppresses one rule on the
next entry:
@comment{badness-lint skip missing-required-field: publisher long gone}
@book{oldbook, title = {An Orphaned Book}}
The directive grammar is the same as in LaTeX. off and on delimit a
region of entries, and skip-file covers the whole file wherever the directive
appears:
@comment{badness-lint off missing-required-field: imported, incomplete by design}
@book{oldbook, title = {An Orphaned Book}}
@comment{badness-lint on missing-required-field}
The <id> is optional. Omitting it suppresses every rule over the same span.
Parse diagnostics (rule id parse) are never suppressed.