The `||` vs `??` Trap That Broke 30% of User Avatars
This bug is a rite of passage for every JavaScript developer, but it's also a production-level reminder that subtle operator semantics can silently corrupt data display at scale. For teams building UIs that handle user-generated content, scores, or status flags, the `||` vs `??` distinction isn't academic — it's a reliability issue that directly impacts user trust.
A production incident last Friday saw 30% of user avatars go blank, despite the avatar API returning valid data. The root cause was a seemingly innocuous line of code: `const avatarUrl = user.avatar?.url || '/default-avatar.png'`. The `||` operator treats all falsy values — including empty strings — as 'not present', so when the avatar service returned `url: ""` for users whose image processing had failed, the default avatar was shown instead.
The fix was straightforward: switch to the nullish coalescing operator `??`, which only falls back on `null` or `undefined`, preserving empty strings, `0`, and `false`. The team also added an ESLint rule (`@typescript-eslint/prefer-nullish-coalescing`) and a code review checklist item to catch future misuse.
Beyond avatars, the same pattern causes bugs with scores of `0` showing as 'No data', CSS classes being overwritten by empty strings, and confusion around function default parameters (which behave like `??`, not `||`). The golden rule: use `??` when you mean 'no data', and only use `||` when you explicitly want to filter falsy values like empty user input.
The bug reveals a common semantic mismatch: backend APIs often use empty strings to signal 'exists but broken', while frontend logic treats empty strings as 'absent'.
The `||` operator is a legacy from early JavaScript when `??` didn't exist; many codebases still default to `||` out of habit, not intent.
Adding an ESLint rule is a good start, but the real fix is cultural — teaching developers to think about what 'no data' means in their specific domain.
The incident highlights how a single line of code can cause a 30% data corruption bug, underscoring the value of defensive programming and explicit null handling.
Function default parameters being `undefined`-only is a common point of confusion; the article's warning is well-placed.