File upload testing: 25 cases most teams miss
Someone drags a 4 MB photo into the avatar box, it appears, and the ticket gets marked done. Two weeks later a customer uploads a scanned contract called contrato_final(2).pdf, the page shows a spinner forever, and the console reads 413 Payload Too Large.
Upload is a small feature with a very wide surface. The file upload testing checklist below is what a full pass looks like.
Short version
- Test the size limit at three points: zero, exactly at, and one byte over.
- A file extension is a claim, not a fact. Rename files and see what happens.
- Filenames carry the most surprises: accents, quotes, dots, and 255 characters.
- Interrupt the upload on purpose. Cancel, go offline, close the tab.
- Check what happens after upload: thumbnails, download names, and who can open the file.
Before you start
Two terms, in plain English.
A MIME type is the label a browser or server uses to say what kind of file this is, such as image/png or application/pdf. It is sent with the upload and it is easy to fake.
A magic number is the first few bytes inside a file that reveal its real type. A real PNG always starts with the same bytes, whatever the file is called. Safe validation checks those bytes, not the extension.
Run everything below on https://staging.example.com as [email protected]. Keep a folder of test files so you can repeat the pass in ten minutes next release.
Size limits
- Upload a 0-byte file. Create it with
touch empty.pdf. The app should reject it with a clear message, not save an unopenable record. - Upload a file exactly at the limit. If the limit is 10 MB, use a file of exactly 10,485,760 bytes. It must succeed.
- Upload a file one byte over the limit. It must fail before the upload starts, not after two minutes of progress bar.
- Upload a 2 GB file. Watch for a browser tab that freezes and for a server that returns
413 Payload Too Largewithout a friendly message. - Select many files at once so the total goes over the limit while each file is under it. Some apps check each file and miss the total.
Type and MIME spoofing
- Rename
virus.exetophoto.jpgand upload it. The app should detect the real type from the file contents and reject it. - Rename a real PNG to
report.pdf. The opposite case. A safe app either rejects the mismatch or trusts the contents, but it must never show a broken PDF viewer. - Upload a file with no extension at all, named just
invoice. Check the error, and check the download filename later. - Upload
report.pdf.exe. Some interfaces show only the first extension, which makes a program look like a document. - Upload an SVG that contains
<script>alert(1)</script>. SVG is an image format that can hold code. If the app shows it inline on your page, that code can run in another user's browser. - Upload a CSV whose first cell is
=1+1or=HYPERLINK("http://evil.example.com"). Spreadsheet software can run that text as a formula when a colleague opens the export. The app should prefix such cells with a quote when it writes CSV. - Upload a zip bomb, a small archive that expands to gigabytes. If the app unpacks archives, this test matters. If it does not, confirm it stores the zip untouched.
Filenames
- Upload
résumé.pdf. Accented characters are the most common real-world failure and often arrive asrésumé.pdf. - Upload
发票.pdfandфайл.pdf. Non-Latin scripts must survive upload, listing, and download. - Upload a file whose name is 255 characters long. Check the list view, the detail view, and the database error log.
- Upload
my "final" report.pdf. Spaces and quote marks break naive download headers and can cut the name in half. - Upload
../../etc/passwd. This is a path traversal attempt, where the name tries to escape the upload folder. The stored file must keep a safe generated name. - Upload
.hidden. A leading dot makes a file invisible on some systems and can produce an empty display name. - Upload
CON.txt. On Windows,CON,PRN,AUX, andNULare reserved names that can fail in strange ways on a Windows server. - Upload
report .pdfwith a trailing space before the extension. Trimming rules differ between the browser, the server, and storage.
Interrupted and slow uploads
- Cancel an upload halfway. Then upload the same file again. There should be no half-saved record and no duplicate.
- Close the tab during an upload, then reopen the page. The item should either be absent or clearly marked as failed, never stuck at 60 percent forever.
- Go offline mid-upload. In Chrome DevTools, open the Network tab and set throttling to "Offline". Expect a clear retry message, not a silent
net::ERR_CONNECTION_RESETin the console. - Let the session expire during a long upload. Sign in on a second tab and sign out, then finish the upload on the first tab. A
401at the end of a five-minute upload must not lose the file without saying so. - Press the browser back button during an upload, then go forward again. Check that the form state and the progress indicator agree with reality.
That is 25. Keep them numbered so a tester can say "case 17 failed" in standup and everyone knows what happened.
Duplicates and repeats
These sit alongside the numbered list because they mostly test your data rules rather than the upload itself.
Upload the same file twice. Decide in advance whether that should create two records, one record, or a warning, then check the app agrees. Upload two different files with the same name and confirm both survive. Delete a file and upload it again with the same name, which often collides with a cached thumbnail. Finally, upload from two tabs at the same time and watch for a duplicate key value violates unique constraint "attachments_key" error in the console.
What a good error message looks like
Most upload bugs that reach support are message bugs, not upload bugs.
| Bad message | Good message |
|---|---|
| "Upload failed" | "That file is 14 MB. The limit is 10 MB." |
| "Invalid file" | "We accept PDF, PNG, and JPG. That file is a ZIP." |
| "Error 413" | "That file is too large to upload. Try a smaller one." |
| A spinner that never stops | "Upload stopped because you went offline. Retry." |
| "Something went wrong" | "Your session expired during the upload. Sign in and try again." |
The pattern is the same in every good row: say what happened, say the limit or the allowed set, and say what to do next.
When you report a failure, attach the console output and the failed network request alongside the screenshot. That is the difference between a developer reproducing it in five minutes and asking you three questions first. Tools such as Crosscheck capture the screenshot, console logs, network requests, and browser details in one step from the page where the upload failed.
After the upload
The file is stored. The bugs are not over.
- Check the thumbnail. A PDF, a rotated phone photo, and a very wide image all need different handling. Photos taken in portrait often appear sideways because the rotation is stored as metadata.
- Download the file and look at the saved name. Accents, spaces, and quotes usually break here rather than on upload.
- Copy the file URL and open it in a private window with no session. If it opens, the file is public. Confirm that is intended.
- Sign in as a user in a different workspace and request the same file by its ID. This is the single most valuable upload test you can run, and it fails more often than teams expect.
- Delete the record and request the file URL again. Deleted should mean gone, not hidden.
How to fit this into a release
You will not run 25 cases every sprint. Split the list.
Run cases 1 to 5, 13, 21, and the access check on every release. They take ten minutes and cover the failures customers actually hit.
Run the full list when upload code changes, when a new file type is added, or before a security review. Keep your test files in a shared folder so nobody has to recreate a 255-character filename by hand at 5pm on a Friday.
Frequently asked questions
How do I create a file of an exact size for testing?
On macOS or Linux, run mkfile 10m big.pdf or dd if=/dev/zero of=big.pdf bs=1m count=10. Adjust the count to go one byte over the limit for case 3.
Is checking the file extension enough validation? No. An extension is just text in the filename and anyone can change it. Safe apps check the bytes inside the file and confirm they match the type the app expects.
Why does an SVG upload count as a security test? SVG images can contain scripts. If your app shows an uploaded SVG inline, that script runs in the browser of whoever views it, which lets an attacker act as that user.
Should the app block duplicate uploads? That depends on the product, and the point of the test is to make the rule explicit. Pick the behaviour on purpose, write it in the ticket, then check the app matches.
What is the fastest useful upload test if I only have five minutes?
Upload a 0-byte file, a file one byte over the limit, and résumé.pdf, then open one stored file from a different account. Those four steps find size, validation, encoding, and access bugs.




