How do you know the reading is right?
The checks that actually catch a wrong table extraction, which of them a library can run for you, and the one thing none of them prove. Written because the question has plenty of articles and almost no code.
Search for how to validate a PDF table extraction and you get evaluation papers, vendor posts and a list of things you should implement. Almost none of it is code you can install. This page is the list, and what each item costs you here.
The reason the question matters at all: a wrong reading does not look wrong. It comes back as a table, with the right number of columns and plausible values in them, and nothing downstream can tell it apart from a right one. Nobody re-reads a table that looks correct.
The checks, by what they catch
1. The cut invented a column
A column filled on 2% of rows is not a column. It is a header, a page number, or a stray mark that the cut mistook for structure — and every row it touched is now shifted.
readTable reports it, with no setup at all:
column 5 of page 1 is filled on only 2% of its rows - the cut may have invented it
2. The pages disagree
Six columns on two pages, seven on a third, means one page was read differently from the others. Anything that concatenates the pages afterwards is mixing two readings.
Also reported by readTable, for free.
3. A row does not look like the others
The row with an empty date where every other row has one is not a row of the table. It is a total, a balance, a footer. Fold it into your sum and the sum doubles.
findRowAnomalies learns the table’s own shape and finds it, without a list of forbidden words — so it works on an issuer nobody has seen, in a language nobody on the team reads. This is the check most homegrown readers skip, and the one that silently corrupts totals.
4. The reading contradicts what the document says about itself
The strongest check available, and the only one that can say a reading is wrong rather than merely odd. A statement declares a total. A payslip declares a net. Add up what you read and compare.
You write the comparison, because only you know what your document declares — selfCheck is the method the pipeline makes compulsory. What the library enforces is the consequence: a reading that contradicts its document never comes back as sound. Not a convention, not a code review item. The pipeline will not return that verdict.
Saying { nothing: 'why this document declares nothing' } is allowed and costs a sentence. That is the point — the oversight becomes something written down instead of a silent null.
5. It is not the document you think it is
A payslip carries dates, amounts and totals. So does an invoice. A reader pointed at the wrong kind of document does not crash; it reads it, and hands you records built from the wrong meaning.
classify is where you say what the document has to look like. The corpus of things it must be told apart from is yours — nobody else knows what lands in your inbox.
6. It has no text at all
A scan is a picture of a table. Every reader must refuse it rather than return zero rows and let an empty result pass for an empty document. open refuses it by name — no-text — along with empty, oversized and password-protected files.
What you cannot check by reading the result
Numbers 1 to 6 look at one document. They say nothing about whether your reader still does this next month, after the refactor nobody thought was risky.
selfCheck() { return null } compiles, passes review and ships. One of the two readers this library came from had exactly that, until it was measured from the outside. So the kit turns the six rules into assertions that run in your test suite, against your corpus, with your extractor — a conformance suite that supplies the extractor stops measuring your reader and starts measuring itself.
The thing none of this proves
An empty list of warnings is not a promise that the reading is right.
It means nothing looked wrong from the shape of the page, which is a much smaller claim, and the difference between the two is the whole reason this library exists. A check can catch a reading that contradicts itself or its document. No check can confirm that a self-consistent reading matches the ink.
That is why the honest output is three-valued — read, needs review, refused — and why refusing matters more than any single test.
Where to go next
- Quickstart — checks 1, 2 and 6 in two lines.
- signature — check 3, and why it beats a word list.
- contract — check 4, the shape it makes compulsory.
- kit — the six rules in your own gate.