Skip to content
>_ TrueFileSize.com
··8 min read

Fix Corrupt File Upload Errors — Why Uploaded Files Get Corrupted

Your uploaded files are corrupted — images won't open, PDFs show blank pages, ZIPs fail to extract. This is one of the most common and frustrating bugs in web development. Here's how to diagnose and fix it.

Common Error Messages

If you're googling one of these, you're in the right place:

  • "The file is damaged and could not be opened"
  • "This file does not appear to be a valid PDF"
  • "Not a JPEG file: starts with 0xef 0xbb"
  • "Error: Unexpected end of JSON input"
  • "Archive is corrupted or has an unexpected end"
  • "Error reading file: premature end of file"

Root Cause 1: Binary File Treated as Text

The #1 cause of file corruption during upload. If your server reads the file body as UTF-8 text instead of binary, every non-ASCII byte gets mangled.

Symptom: Uploaded file is slightly larger than original, images show garbage.

Fix (Node.js/Express):

// WRONG — body parsed as text
app.use(express.text({ limit: '10mb' }));

// RIGHT — use multer for file uploads
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('file'), (req, res) => {
  // req.file.path contains the binary file
});

Root Cause 2: Wrong Content-Type Header

Sending a file with Content-Type: application/json instead of multipart/form-data corrupts the payload.

Symptom: Server receives garbled data, file size doesn't match.

Fix (Frontend):

// WRONG — manually setting Content-Type breaks multipart boundary
fetch('/api/upload', {
  method: 'POST',
  headers: { 'Content-Type': 'multipart/form-data' }, // DON'T DO THIS
  body: formData,
});

// RIGHT — let the browser set Content-Type with boundary
fetch('/api/upload', {
  method: 'POST',
  body: formData, // Browser auto-sets Content-Type with boundary
});

Root Cause 3: Incomplete Transfer (Truncation)

Network timeout, client disconnect, or server body size limit causes partial upload.

Symptom: File is smaller than expected, opens partially or not at all.

Fix: Compare sizes and implement chunked upload:

app.post('/upload', upload.single('file'), (req, res) => {
  const expectedSize = parseInt(req.headers['content-length']);
  const actualSize = req.file.size;

  if (actualSize !== expectedSize) {
    fs.unlinkSync(req.file.path); // Delete corrupt file
    return res.status(400).json({
      error: 'Incomplete upload',
      expected: expectedSize,
      received: actualSize,
    });
  }
  // File is complete
});

Root Cause 4: Base64 Encoding Issues

Sending binary files as base64 without proper decoding corrupts them.

// WRONG — double-encoding
const base64 = Buffer.from(file).toString('base64');
const decoded = Buffer.from(base64, 'utf8'); // WRONG encoding param

// RIGHT
const decoded = Buffer.from(base64, 'base64'); // Correct

Debug Checklist

  1. Compare file sizes: ls -la original.pdf uploaded.pdf — should be identical
  2. Compare checksums: md5sum original.pdf uploaded.pdf
  3. Check first bytes: xxd original.pdf | head -1 vs xxd uploaded.pdf | head -1
  4. Check Content-Type header: Must be multipart/form-data with boundary
  5. Check server body parser: Must handle binary, not text

Test with Sample Files

Download files with known-good checksums to test your upload pipeline:

| Test | File | Expected | |------|------|----------| | Basic upload | sample-1mb.pdf | File opens correctly | | Image upload | sample-500kb.jpg | Image displays | | Large upload | sample-10mb.mp4 | Size matches exactly | | Already-corrupt | sample-corrupt.pdf | Your error handling works |

After uploading, verify: md5sum original.pdf === md5sum uploaded.pdf. If they differ, the upload pipeline is corrupting data.

Prevention

  1. Always use multipart/form-data for file uploads
  2. Never manually set Content-Type when using FormData
  3. Use multer (Node), Busboy, or formidable — not express.json() for files
  4. Validate file size after upload matches Content-Length
  5. Test with corrupted files to verify error handling