Blog

How to Test File Upload Limits: A Practical Guide

Testing an upload limit properly means three exact files, not one: at the limit, one byte over, and comfortably under — here's how and why.

Every file upload form has a size limit somewhere — sometimes documented, sometimes not, and sometimes wrong. Testing it properly means more than dragging in a random file and seeing what happens.

Why "roughly the right size" isn't good enough

A file that's "about 10 MB" tells you almost nothing. If the upload fails, was it because your limit is 10 MB and the file was 10.2 MB? Or is the real limit 8 MB and you got lucky with a smaller file last time? Without an exact byte count, every failed test raises a new question instead of answering the one you started with.

Proper limit testing needs three files, not one:

  • Exactly at the limit — should succeed.
  • One byte over — should fail, with a clear error, not a silent timeout or a 500.
  • Comfortably under — a sanity check that the happy path still works.

The off-by-one trap

The most common bug in upload-limit code isn't the limit itself — it's the comparison operator. A check written as size > maxSize behaves differently from size >= maxSize at exactly one byte: one rejects a file that's exactly at the limit, the other doesn't. Most APIs and platforms don't document which one they use, and the only way to find out is to send a file at exactly that boundary and read the response.

This also catches a second, sneakier bug: systems that accept the upload over the wire and only reject it afterward, once the full file has already consumed bandwidth and hit disk or memory. A slow rejection after a full upload behaves very differently under load than a fast rejection at the start — and you only notice the difference by testing at the actual boundary, not somewhere comfortably below it.

Reference: limits worth knowing

A few commonly cited limits, useful as starting points for your own tests (these can vary by plan and change over time, so verify against current documentation before relying on them):

| Where | Limit |

|---|---|

| Discord, free attachment | 25 MB |

| Gmail, attachment | 25 MB |

| Outlook.com, attachment | 33 MB |

| AWS API Gateway, payload | 10 MB |

| PHP, default upload_max_filesize | 2 MB |

| GitHub, file in a repo (soft warning) | 50 MB |

| GitHub, file in a repo (hard block) | 100 MB |

Every one of these is a target for the same three-file test: at the limit, one byte over, comfortably under.

Generating the exact files

This is the part that usually takes longer than it should — most "sample file" tools give you a file that's close to a size, not exactly it, because they're built around fixed presets or padding that rounds to the nearest KB. For a boundary test that's the whole problem.

ByteRivet's test file generator takes an exact byte count — not a preset, an arbitrary number you type in — and builds a real file of that exact size in your browser. Pick a format, type 26214400 (or 25 × 1048576, however you prefer to think about it) into the exact-size field, and the file it hands you is that many bytes, not approximately that many. Nothing uploads anywhere to generate it; the browser does the work and hands you a download.

For the one-byte-over test, that precision matters even more — you need 26214401, not "whatever the generator felt like rounding to."

A quick checklist

  • Test at the documented limit, not near it.
  • Test one byte over the limit — confirm the failure is fast and the error message is useful.
  • Test comfortably under the limit as a control.
  • Check whether the rejection happens before or after the full upload completes.
  • Re-run the test after any change to the upload path — limit checks are exactly the kind of code that quietly breaks when someone refactors around it.