
This bug did not come from a complex algorithm.
It did not come from a race condition I barely understood.
It did not come from some edge case.
It came from a wrong assumption.
And what made it worse is that the assumption felt reasonable.
It felt safe.
It felt obvious.
Which is why I didn’t question it.
The App Was “Working”
At the time, I was working on a fairly normal frontend feature.
Nothing fancy.
A page that:
- Fetches data from an API
- Displays a list
- Allows the user to interact with it
- Updates the UI based on state
The kind of thing I had built many times before.
The app worked.
The UI looked correct.
There were no errors in the console.
No crashes.
No warnings.
QA tested it.
Product was happy.
I moved on.
That’s usually how bugs begin.
Not with failure.
But with false confidence.
The Assumption I Made
Here was my assumption:
“This data will only change when the user explicitly triggers an action.”
So I wrote my code around that idea.
I assumed:
- The API response shape would stay consistent
- The data would not update in the background
- State changes would only happen in one place
- A component would render once per user action
Because that’s how it worked during development.
And that’s a dangerous sentence.
How the Assumption Shaped the Code
Because of this assumption, I did a few things that felt harmless at the time.
Derived state from props (once)
const [items, setItems] = useState(props.items)
Skipped dependencies in useEffect
useEffect(() => {
fetchData()
}, [])
Memoized aggressively
const processedItems = useMemo(() => {
return items.filter(item => item.active)
}, [])
Everything looked clean.
Short.
Readable.
I remember thinking:
“Nice. This is simple.”
It was simple because it was incomplete.
The Bug Appeared Later
Weeks later, someone reported a strange issue.
Not always reproducible.
Not happening for every user.
Not crashing the app.
Just… wrong behavior.
Sometimes:
- The list showed outdated data
- A button stopped responding correctly
- A value on the screen didn’t match the backend
Refreshing the page fixed it.
That made it worse.
Because now it felt like:
- Maybe a network issue
- Maybe caching
- Maybe user error
Classic excuses.
My First Reaction
My first reaction was not curiosity.
It was defense.
“I didn’t change anything there.”
“That code is stable.”
“It’s been live for weeks.”
This is another quiet mistake we make.
We trust time instead of logic.
Just because code has existed without obvious failure does not mean it’s correct.
Digging Into the Problem
Eventually, I sat down and really looked at it.
I added logs.
I slowed things down.
I tried to reproduce it locally.
Slowly, a pattern appeared.
The data was changing.
Just not when I expected it to.
There was:
- A background refetch
- A shared store update
- Another component mutating the source
The data changed without user interaction.
And my component did not react to it.
Because I told React:
“Don’t worry. This never changes.”
That was the assumption.
The Exact Moment It Clicked
I stared again at this line:
const [items, setItems] = useState(props.items)
And asked myself:
“When does this update?”
The answer was simple.
Only once.
Because that’s how useState works.
I had assumed:
Props change → state updates automatically
But React never promised that.
That belief came from my own mental shortcut.
Why This Bug Was Dangerous
This bug wasn’t loud.
It didn’t:
- Throw errors
- Break builds
- Fail tests
It quietly made the UI drift out of sync with reality.
Those are the worst bugs.
Users don’t report them clearly.
They just lose trust.
They think:
- “Sometimes it works”
- “Sometimes it doesn’t”
And eventually, they stop using the product.
The Real Root Cause
The bug wasn’t:
- React
- Hooks
- The API
- The backend
The real cause was this:
I designed the code around how I expected the system to behave, not how it actually behaved.
I optimized for a scenario that existed only in my head.
Fixing the Bug
The fix was not complex.
I:
- Removed derived state where it wasn’t needed
- Let props stay as props
- Added real dependencies to effects (and stopped making this mistake with useEffect)
- Allowed re-renders to happen naturally
const items = props.items
useEffect(() => {
process(items)
}, [items])
The code became slightly longer.
Slightly less “clean”.
But much more honest.
And that mattered more.
What I Learned From This
1. Assumptions Are Invisible Bugs
They don’t show up in code reviews easily.
They show up as thoughts like:
- “This will never change”
- “We don’t need to handle that”
- “It’s safe to ignore this case”
That’s where bugs grow.
2. Working Code Can Still Be Wrong
If the UI looks fine today, it doesn’t mean it will look fine tomorrow.
Especially when:
- Data changes over time
- Multiple parts affect the same state
- The app grows
Silence is not proof of correctness.
3. Simplicity Can Be Misleading
Simple code is good.
But oversimplified assumptions are not.
Complexity doesn’t disappear just because you ignore it.
It waits.
4. React Does Exactly What You Tell It To
React didn’t betray me.
It followed my instructions perfectly.
I told it:
- Initialize once
- Don’t re-run
- Trust this value
It trusted me.
That trust was misplaced.
How I Think About Code Now
Now, I ask different questions.
Not:
“Does this work right now?”
But:
- “What am I assuming here?”
- “What breaks if this changes?”
- “What am I telling React to ignore?”
I care less about:
- Fewer lines
- Clever tricks
- Early optimization
And more about:
- Clear behavior
- Honest dependencies
- Predictable updates
A Small Mental Shift
One idea helped me a lot:
Treat assumptions as bugs that haven’t happened yet.
If your code relies on something never changing, write that down.
If it feels “obvious”, question it.
Because software rarely stays the way we imagine it.
Final Thought
This bug didn’t make me feel smart.
It made me feel humbled.
The mistake wasn’t technical.
It was human.
I assumed.
I trusted that assumption.
And I built on top of it.
Now, I still make assumptions.
But I try to notice them.
Because most bugs don’t come from what we don’t know.
They come from what we’re too sure about.
☕Did you like the article? Support me on Ko-Fi!
