| Dave | 5 min read

Edge Cases Are Not Edge Cases. They Are the Product.

The 'edge cases' discovered during development are usually planning failures. Here's why PMs should catch them during requirements, not QA.

The thing your spec didn’t cover

A developer raises their hand during sprint review. “What should happen when the user has no data?”

Silence. Nobody thought about that.

It’s called an “edge case,” and that label is part of the problem. Calling it an edge case implies it’s rare, unlikely, someone else’s problem. But the empty state isn’t rare. Every single new user hits it. It’s literally the first thing they see.

This isn’t an edge case. It’s the product. And it should have been in the spec.

Why “edge cases” keep showing up in development

When PMs write requirements, they tend to describe the happy path. The user has data. The connection is fast. The input is valid. Everything works as expected. That’s the easiest scenario to think about and the one that matches the demo in your head.

But your users don’t live on the happy path. They live in a messy world where they mistype emails, lose WiFi on the bus, use your product in ways you never imagined, and hit back when they shouldn’t.

Every “edge case” discovered during development is a planning failure. Not because PMs should predict everything. They can’t. But the common ones? Those should be in the spec before the first line of code.

5 “edge cases” that should be in every spec

1. The empty state

What does the user see when they have no data? No projects, no messages, no results. This isn’t an edge case. It’s the new user experience.

A good spec defines: what message does the user see? Is there a call to action? Does the UI change once they add their first item?

2. The slow connection

Your product works great on your office WiFi. What about on a 3G connection in a train tunnel? What about when the API takes 8 seconds instead of 200 milliseconds?

Specify: what happens during loading? Is there a timeout? What does the user see if the request fails? Can they retry?

3. The invalid input

Users will paste emoji into number fields. They’ll submit forms with spaces where you expect URLs. They’ll upload a 200MB file when you expected 2MB.

Specify the validation rules. What’s accepted, what’s rejected, and what error message appears. Don’t leave it to the developer to make up error copy on the fly.

4. The concurrent action

Two people edit the same document. A user clicks “submit” twice. Someone deletes an item while another person is viewing it.

These aren’t obscure scenarios. In any collaborative or multi-device product, they’re daily occurrences. Define the behaviour: last write wins? Conflict resolution? Optimistic locking?

5. The permission boundary

What happens when a user tries to access something they don’t have permission to view? Do they see a 404 (pretend it doesn’t exist) or a 403 (you can’t access this)? What about when their permissions change while they’re in the middle of a session?

These decisions affect security and user experience. They deserve deliberate choices, not whatever the developer implements at 5pm on a Friday.

How to think about edge cases during requirements

You don’t need to anticipate every possible scenario. That’s not realistic. But you can build a habit of asking three questions for every feature:

What if there’s nothing? Empty states, zero results, no data, new user with no history.

What if something goes wrong? Network failure, server error, validation failure, timeout.

What if the user does something unexpected? Double submission, back button, browser refresh, unusual input, concurrent access.

These three questions catch 80% of the “edge cases” that show up during development. They take 10 minutes to think through per feature and save hours of back-and-forth later.

The cost of not thinking about it

When edge cases aren’t in the spec, one of two things happens.

The developer makes a decision. Sometimes it’s a good one. Sometimes they hard-code an error message that says “Something went wrong” and move on, because they have a sprint to finish and the PM didn’t specify what should happen.

Or the developer raises it, the PM thinks about it, a conversation happens, maybe a designer gets involved, and a decision gets made mid-sprint. That’s rework. It’s unplanned work that disrupts the flow and extends the timeline.

Neither outcome is good. Both are avoidable.

Reframing the language

I’d encourage every product team to stop using the phrase “edge case.” Call them “alternate paths” or “failure states” or just “requirements we haven’t written yet.”

The language matters because it changes how seriously people take them. An “edge case” sounds optional. A “requirement we haven’t written yet” sounds like a gap that needs filling.

Your product isn’t just the happy path. It’s every path. And the paths you don’t plan for are the ones that frustrate your users the most.

Write them down. Before the sprint starts.

Stop writing PRDs from scratch

Try Projan free for 14 days. Beta users get 50% off for life.

Start Free Trial