Filename test cases that break real systems
A surprising share of file-handling bugs have nothing to do with the file. They are in the name, which passes through more systems, with more conflicting rules, than the bytes ever do.
A name written by a user has to survive a URL, an HTTP header, your application code, a database column, an object-storage key and finally a filesystem. Each of those disagrees with the others about what is legal.
The cases that find bugs
- Spaces and punctuation,
report (1) [copy] #2 & final.pdf. Breaks unquoted shell commands, unencoded URLs and naive CSV manifests. The ampersand and hash are the dangerous characters in a URL. - A 255-character name, the usual filesystem maximum. Overflows short database columns, and can exceed a path limit once your storage prefix is prepended even though the name alone was legal.
- Non-ASCII and emoji,
tést-文件-файл-📄.pdf. Catches encoding assumptions in storage, in HTTP headers, and in any code that measures length in bytes while the user counts characters. - A leading dot,
.hidden.pdf. Invisible in Unix directory listings, which makes a file that was created but cannot be found. - Many extensions,
archive.v2.backup.final.zip. Defeats any code that finds the type by splitting on the first dot instead of the last. - Windows reserved device names:
CON,PRN,AUX,NUL,COM1,LPT1. These are device names, not filenames, and Windows refuses to create a file calledCON.pdfat all.
What a browser does to a reserved name
This one is worth knowing because it changes how you interpret the test. Downloading a file named with a Windows reserved device name in Chrome on Windows does not fail and does not save CON.flv, the browser saves it as _CON.flv, quietly prepending an underscore.
That is observed behavior, not documentation: a file generated here with the reserved-name style arrived on disk with the underscore added. So a direct download cannot deliver a genuinely reserved name to your filesystem, and a test that relies on one will silently test something else.
The way around it is a container. Names inside a ZIP are just strings in the archive's own directory and are not touched by the browser, so extracting the archive is what actually hands your system the literal name. That is why choosing more than one file condition here, which produces a ZIP, preserves awkward names exactly.
Chrome and Firefox disagree, measured
The same six styles were downloaded in Chrome 150 and Firefox 153 on Windows and read back off the disk. Three of the six behave differently, which matters the moment you compare results between browsers.
- A reserved device name saves in both, under a different substitute: Chrome writes
_CON.json, Firefox writesUntitled.json. Neither refuses outright, so a test expecting a hard failure will not see one. - A 255-character name saves in Firefox, truncated to roughly 204 characters. In Chrome nothing arrives at all: the download stalls, leaves a partial file and reports nothing to the user. The name plus any directory exceeds the 260-character path limit Windows still applies by default.
- A leading dot survives in neither. Both browsers strip it before writing, so
.report.pdflands asreport.pdfand is not hidden anywhere. - Spaces, punctuation, accented characters and emoji arrive intact in both.
Where these names actually break
- Shell commands built by string concatenation, a space splits one argument into two, and an ampersand ends the command.
- URLs,
#truncates the path at a fragment,?starts a query string, and a space is not legal unencoded. - HTTP headers. A non-ASCII name in Content-Disposition needs the encoded form, or the download arrives mangled.
- Database columns. A name that is legal on disk still fails to insert into
varchar(64). - Object storage. A leading dot or a doubled slash can produce a key you cannot address afterward.
- Case sensitivity,
Report.pdfandreport.pdfare one file on Windows and macOS, two on Linux. This is how duplicate-detection bugs appear only in production.
What to assert
- The name is stored and displayed as the user provided it, including non-ASCII characters.
- The name is never used directly as a filesystem path or a shell argument.
- A name too long for storage is rejected clearly, or truncated deliberately, not silently cut mid-character.
- Downloading the file again returns the original name intact.
Common questions
Why can I not create a file called CON on Windows?
CON is a reserved device name, along with PRN, AUX, NUL, COM1 to COM9 and LPT1 to LPT9. Windows resolves them as devices rather than files, so the name cannot exist even with an extension added.
How do I get a file with an awkward name onto my machine?
Download it inside a ZIP. Browsers sanitize download filenames, Chrome on Windows turns a reserved name into _CON.ext, but names inside an archive are untouched, so extracting delivers the literal name.
How long can a filename be?
Most filesystems allow 255 characters for a single name, but the full path is limited separately, so a legal name can still fail once your directory prefix is added. Test both the name limit and the path limit.
Generate a file with an awkward name →
Formats mentioned here: PDF test files · CSV test files · ZIP test files · PNG test files · DOCX test files
More guides
How to create a very large test file · How to create an invalid JSON file for testing · How to make a corrupted file for testing · How to test file upload validation · Encoding test files: UTF-16, BOM and Latin-1