Repair PDF

Diagnose a broken PDF and rebuild it — structurally if possible, visually if not.

About Repair PDF

A PDF that will not open is usually not a PDF with damaged pages. It is a PDF with a damaged index. This tool reports exactly which structural parts are missing, then tries to rebuild the file — first properly, and if that is impossible, visually. The repaired copy downloads as repaired-yourfile.pdf and your original is left alone.

Why PDFs break the way they do

A PDF is a pile of numbered objects with a lookup table at the end. The reader starts at the very last line, finds startxref, jumps to the byte offset it names, reads the cross-reference table, finds the trailer, follows it to the document catalogue, and only then reaches your pages. Every step of that chain is a byte offset into the file. Break one and the whole document becomes unreadable even though every page is still intact a few kilobytes away — which is why a truncated download, a file edited by something that got the offsets wrong, or a transfer that mangled line endings produces a document a reader flatly refuses while all the content sits there untouched.

What the diagnosis is looking at

The raw bytes are decoded as latin1 and scanned for the pieces of that chain: the %PDF- header and how far into the file it starts, the count of N G obj object headers and matching endobj markers, stream count, /Type /Page objects, cross-reference data in either of its two forms — a classic xref table with its subsection header, or the /Type /XRef cross-reference stream that has replaced it in most files written since PDF 1.5 — a trailer dictionary, a startxref pointer, a /Type /Catalog and a /Type /Pages node, the final %%EOF and how many bytes come after it, duplicate object numbers, the marks of an /Encrypt dictionary, and the number of %%EOF markers, which is usually the count of appended revisions. The patterns are shaped like PDF syntax rather than like words, because plain prose renamed to .pdf contains "xref" and "stream" often enough to fake a healthy scan.

Two of those checks follow the offset rather than stopping at the keyword, because the presence of a pointer says nothing about whether it points anywhere. The byte offset startxref names is resolved and read: if it is past the end of the file, or lands on something that is neither a cross-reference table nor an object header, that is reported as an error even though the keyword is right there. And where it lands on a classic table, the table's own in-use entries are followed — up to four hundred of them — to confirm each really does reach the object it names. A table where none of them do is the single most common reason a document with every page intact is refused by every reader, and a scan that only counted keywords would call that file healthy. Files with junk before the header are handled the way readers handle them, by measuring offsets from %PDF- as well as from byte zero, so a shifted-but-consistent file is not accused of damage it does not have. Junk after the end is measured the same way: a document whose last %%EOF is buried under an appended transfer artefact is complete, and calling that a truncated download would be the wrong fault with the wrong advice, so the distance is reported instead.

Every check that fails becomes a named issue with a severity. Where compressed object streams are in use, the checks that cannot see inside them are marked inconclusive rather than failed — a modern PDF keeps its catalogue and page tree inside one, and a scan that called that damage would be crying wolf on a healthy file.

The two strategies

  • Strategy 1 — structural rewrite. The document is parsed and written back out, which regenerates the cross-reference table, the trailer and every offset from scratch. It runs strictly first and, if an object will not parse, again in a tolerant mode that skips it. This path is lossless: text stays text, images keep their original encoding, and nothing is re-encoded, though the size can move a few percent either way because the object layout is rebuilt.
  • Strategy 2 — visual rebuild. When the writer cannot parse the file, or when what it wrote fails verification. It is a completely separate parser — pdf.js, with its own recovery path for damaged cross-reference data — and the two fail on different things, so a document one gives up on is sometimes still readable by the other. Each page it can open is drawn at 144 DPI, encoded as a JPEG and placed into a new page the size of the area a reader displays — the crop box, which for almost every document is the whole page. Pages larger than a canvas can hold are drawn at a lower resolution and the log says so. Pages that throw are skipped and counted rather than aborting the run.

The result panel names the strategy that worked, which matters: Strategy 1 gives you your document back, Strategy 2 gives you a picture of it. If you land on Strategy 2 and need the words, OCR PDF will read the recovered images and write a fresh searchable text layer.

How the repair is proved

A tolerant parse can skip an object and quietly hand back a document with a page in it that no reader can open, and a page count on its own would not reveal that. So the repaired bytes are handed to a second, independent parser — pdf.js, with no password and no encryption escape hatch — which opens the file, opens every page in it one at a time, and reads the text. A rewrite that parser cannot open at all is discarded and the next strategy runs; a rewrite that loses all its text when the original had text is discarded too. Pages that come through still broken are counted separately and never folded into the pages-verified figure, so the number on the result panel is a number a reader has confirmed rather than one the writer asserted.

A page count is not the whole story either, so the text is compared as well. A re-serialised page is the same drawing instructions, so the same reader pulls the same characters out of it — the counts match exactly on an undamaged rewrite. When they do not, something moved: the usual cause is a damaged file holding two versions of one object, where the rewrite kept the version the reader was not using, and the result is a page that opens perfectly and is blank. That is invisible to every count a repair tool normally reports, so when the repaired copy gives up measurably less text than the original did, the result panel says so in as many words rather than showing a green tick over a missing page.

One parser is one parser, and the honest limit of this check is worth stating. When the strict parse fails and the tolerant one takes over, objects that would not parse are carried through as they were found; the result is a file pdf.js can open every page of, but the damaged object is still in there and a stricter reader may refuse it. The result panel says so whenever tolerant mode was used, and the visual rebuild is the way out if you meet a reader that will not have it.

pdf.js is also asked what it makes of the original before any of this — every page opened one at a time, exactly as the repaired file is checked — so the two counts can be compared like for like. That distinction matters: a damaged page tree routinely lists pages the renderer cannot open, and counting those would advertise a visual rebuild that recovers the same pages minus the text layer. If the renderer can genuinely open more pages than the rewrite kept, the log says so, the result panel repeats it, and the visual rebuild is offered as a deliberate second choice — a lossless file with a page missing and a lossy file with every page are both defensible outcomes, and which one you want is not something a tool should decide for you. Whichever you pick, the other is kept: one button switches back.

Encrypted files

An encrypted PDF cannot be re-serialised and left carrying its encryption dictionary: the key is derived from the file, so a rewritten copy no longer matches its own key and every reader refuses it. This tool therefore treats encryption head-on. It starts by establishing whether the file is encrypted at all, because the byte scan cannot tell: an /Encrypt reference stranded in an old revision reads exactly like a live one. The trailer is parsed without decrypting, and pdf.js is asked whether it sees restrictions in force; nothing is said about decryption unless one of them confirms there was an encryption dictionary to remove. A file with permission restrictions only — one that opens for anyone but blocks printing or copying — is decrypted with an empty password, and the rewrite deliberately drops the leftovers a decrypting parse leaves behind: the input's own cross-reference stream, its object streams and its encryption dictionary are all carried into the parse as ordinary objects, and the old cross-reference stream's dictionary is the old trailer, so leaving it in would plant an /Encrypt entry — pointing at an object that no longer exists — inside a copy being described as carrying none.

Then the claim is checked instead of asserted, on the bytes that were actually produced. They are scanned for any surviving /Encrypt, and the verifying reader is asked separately whether it still sees permission restrictions in force. The result panel says the encryption is gone only when both come back clean; if a reader still reports restrictions it says so plainly and points at Unlock PDF, and if nothing is enforced but a disused entry is still in the bytes it says that too. A file that needs a password to open cannot be read without it, and the repair stops and sends you to Unlock PDF rather than writing out a file that would open for nobody. The page-by-page verification is the backstop for all of it: if the repaired copy cannot be opened by an ordinary reader with no password, it is never offered as a repair.

What repair cannot do

It cannot invent data that is not in the file. If a download stopped at 40 percent, the last 60 percent of the pages do not exist anywhere and nothing recovers them — though Strategy 2 will often still return the pages that did arrive. It cannot open a document whose open password you do not have. And it cannot fix a file that was never a PDF: a file the browser does not offer as a PDF is refused at the drop zone with a message, and a file renamed to .pdf gets a diagnosis that says so plainly by finding no header and no objects. Before anything else, try re-downloading the original — a second transfer fixes more broken PDFs than any repair tool does.

Diagnosis before surgery

The raw bytes are scanned for the header, object headers, endobj markers, cross-reference data of either kind, the trailer, the catalogue, the page tree and the trailing %%EOF — and the offsets are followed, not just counted: a startxref that points nowhere and a table whose entries miss their objects are both named before anything is rewritten.

Two strategies, tried in order

A strict structural reload and rewrite first, falling back to a lenient one. If neither parses, the pages are rendered with pdf.js instead and a new PDF is built from them.

The repair is proved, not assumed

The repaired bytes are re-opened by a second, independent parser — pdf.js, with no encryption escape hatch — and every page is opened one by one. The original is measured the same way, so the two counts can be compared like for like. A rewrite that parser cannot read is thrown away, not handed to you.

It tells you which one worked

The log shows each attempt and its outcome, and the result names the strategy that succeeded, how many pages were verified and how the size changed — so you know whether you still have text or only pictures.

Frequently Asked Questions

What kinds of damage can this actually fix?

The structural kind. A cross-reference table whose offsets no longer point at their objects, a missing or malformed trailer, a startxref that points past the end of the file — or that has no number after it at all — junk prepended before the header or appended after the final %%EOF, objects that are present but not correctly indexed, and files truncated after the last complete object. The diagnosis names each of those specifically, because it follows the offsets rather than only checking that the keywords are there. What it cannot fix is missing data: if half the bytes never arrived, the content in them is gone and no tool recovers it.

What is the difference between the two strategies?

Strategy 1 parses the document properly and writes it back out, rebuilding the cross-reference table and trailer from scratch. It is lossless — text stays text, images keep their encoding. Strategy 2 runs automatically when Strategy 1 cannot parse the file or when the file it produced fails verification. It uses a different parser, pdf.js, which has its own recovery path for damaged cross-reference data, so a file one library gives up on is sometimes still readable by the other. Its pages are rendered and re-assembled into a new PDF as images, which recovers the content but not the text layer, links, bookmarks or form fields. You can also ask for Strategy 2 by hand after a successful rewrite; the structural file is kept and one click brings it back.

Is the visual rebuild simply more forgiving? Why not always use it?

Because it is not reliably more forgiving — the two libraries fail on different things. The structural path recovers well from a missing or wrong cross-reference table, because it can scan the whole file for objects and rebuild the index; the renderer copes better with an individual object that is malformed while the surrounding structure is fine. That is why the lossless attempt runs first, and why, when it succeeds, pdf.js is asked separately how many pages of the original it can actually open — every page, one at a time, not just what the page tree claims. Those two numbers come apart precisely when the page tree is damaged, and a page the renderer lists but cannot open is a page the visual rebuild would skip. So the offer to rebuild visually is made only when the renderer can genuinely open more pages than the rewrite kept, and it is offered rather than chosen for you.

The result says Strategy 2. What have I lost?

Selectable and searchable text, links, bookmarks, annotations, form fields and metadata. Every page is now a JPEG at 144 DPI inside a page the size of the area a reader displays. Unusually large pages are rendered at a lower resolution, because a browser canvas cannot exceed roughly 8192 pixels a side nor about 16.7 million pixels in total, and the log names the resolution it fell back to when it happens. It is a real recovery of the content, not of the document. If you need the words back, run the result through OCR PDF, which reads the images and writes a fresh text layer.

Why did it recover fewer pages than the document had?

Strategy 2 renders each page independently and skips the ones that throw, which is the point — one unreadable page in the middle no longer costs you the other forty. The count of skipped pages is reported. Strategy 1 reports the same way: the pages it claims are the pages the verifying parser could actually open in the repaired file, and any page that came through the rewrite still broken is counted separately rather than folded into the good news. There is a third case worth knowing about, because a page count cannot show it: a page that opens but is empty. That happens when a damaged file holds two versions of the same object and the rewrite keeps the one the reader was not using. The repaired copy's text is measured against the original's for exactly that reason, and if it comes back short the result panel says so. Damage is often concentrated in a region of the file, so missing pages are usually consecutive.

It says the file is encrypted. What happens?

First it establishes whether the file really is encrypted. The diagnosis works from the raw bytes, and bytes can lie: an /Encrypt reference left behind in an old revision, or sitting inside an uncompressed stream, looks exactly like a live one. So before anything is claimed, a parser is asked — the trailer is read without decrypting, and pdf.js is asked whether it sees permission restrictions in force — and the repair only talks about decryption when one of them confirms it. Then it depends which kind of protection it is, and the tool checks rather than guesses, twice, on the bytes it actually produced. A file that carries only permission restrictions — no password needed to open it, but printing or copying is blocked — is genuinely decrypted, and the finished copy is then scanned for any surviving /Encrypt entry and handed to a reader to ask whether it still sees restrictions in force. Only if both come back clean does the result say the encryption is gone; if either does not, the panel says exactly what survived and sends you to Unlock PDF, rather than claiming a removal that did not happen. A file that needs a password to open cannot be read at all without it, so the repair stops before writing anything.

Nothing worked. What now?

Three things are worth trying in order. Re-download or re-copy the original, because a truncated transfer is the single most common cause and the second attempt often just works. Check the file size against where it came from. And open it in a plain text viewer to confirm it starts with %PDF- at all — files renamed to .pdf from something else are surprisingly common, and the diagnosis panel will have said so.

Will repairing change the content?

Strategy 1 does not touch page content: the objects are re-serialised, not re-rendered, so the pages are byte-for-byte the same drawing instructions. Metadata is preserved as found rather than restamped — and because the title, author and dates are reached through the trailer, damage that costs a file its trailer would ordinarily cost it those too. So when the pointer to them is missing, it is looked for in the raw bytes; and where the pointer went with the bytes that never arrived, the file is searched for the information dictionary itself, which usually survived with nothing left pointing at it. A candidate is adopted only if it looks like an information dictionary rather than, say, a bookmark that happens to have a title. If the file names one and no readable copy is left, the result says so rather than letting it disappear quietly — and a document that simply never had any metadata is not accused of losing some. The file size can move a few percent either way, because the cross-reference data and object layout are regenerated, but nothing is re-encoded. Strategy 2 changes everything by definition, because it rebuilds from a render. Either way the original file on your disk is untouched — keep it until you have checked the repair.

Is the file uploaded?

No. Diagnosis, both repair strategies, the decryption and the rendering all run inside this browser tab with pdf-lib and pdf.js served from this site. A damaged document is often a document you cannot afford to lose or to leak, and nothing here transmits it anywhere.