A customer’s report was simple: adding a photo to an album kept failing with a generic error and no useful detail. We went looking for why.

The rule we took for a leftover

In the upload code we found a filename rule that only allowed letters, numbers, dots, underscores, and hyphens, and rejected anything else outright. Real photo filenames are full of the characters it refused: spaces, parentheses, apostrophes. A file the file browser had just listed as a normal image could still get turned away with “unsupported file type” for no reason a customer could see.

We read that rule as an overcautious leftover nobody still needed, and removed it. We committed the change believing we had closed a false rejection and nothing more.

Trying to break our own fix

Before calling it done, we built a small harness. It runs a batch of filenames, some ordinary and some deliberately adversarial, through the same code path and checks what comes out the other end.

The ordinary names all passed, as expected. Some of the adversarial ones passed too. Removing the whole-name whitelist had not only stopped rejecting spaces and parentheses. It had also stopped rejecting a kind of file that should never be treated as a photo, something the old rule had been catching as a side effect the entire time. The check had been doing two jobs, and we had only understood one of them.

A narrower rule

Reverting the whitelist was off the table, since real filenames still needed to work. So we wrote a narrower rule aimed directly at the danger the old one had been blocking by accident, while still accepting normal photo names. Run back through the harness, it let every realistic filename through and stopped every adversarial one.

Testing that second fix properly turned up something unrelated. Rotating a photo whose name had a space in it was already broken in production, with no visible error. One piece of code read a filename back out of a web-escaped link and handed it straight to a file lookup that expected the real name. It only surfaced because retesting meant exercising the code with a realistic filename instead of trusting that the earlier change had worked.

What went out

Both fixes shipped together in the next release: the corrected filename rule and the rotation fix, bundled with the original change. The gap between “removed the old rule” and “closed it properly” never reached a live server on its own. The whole sequence, first fix to corrected fix, took about half an hour on a Sunday night.

None of it was the failure the customer had actually hit. That was something else, found later the same night and fixed in the same release.

A rule we could only explain one reason for probably had a second reason we hadn’t found yet. The way to find it was to throw ordinary and deliberately hostile filenames at our own fix before we let ourselves call it finished.