BugHunt

Null and undefined: the crash that happens far from the mistake

Cannot read properties of undefined, NoneType has no attribute, NaN appearing from nowhere.

13 free challenges6 Python7 JavaScript

What is null and undefined error?

A missing value gets used as if it were present. In JavaScript that is undefined or null; in Python it is None. The crash happens where the value is finally used, which is often nowhere near where it went missing.

Why it happens

Lookups that can fail return an empty result rather than raising: Array.find returns undefined, dict.get returns None, an out-of-range index returns undefined in JavaScript. Code then reads a property off it. The gap between where the empty value was created and where it blew up is what makes these hard to trace — the failing line is usually not the wrong line.

How to recognise it

  • The error names a property you are certain exists.
  • NaN appears in a calculation with no obvious source.
  • It works with full data and fails with real, incomplete data.
  • A legitimate 0 or empty string is being treated as missing.

Errors and symptoms this causes

  • TypeError: Cannot read properties of undefined (reading 'x')
  • TypeError: Cannot read properties of null
  • AttributeError: 'NoneType' object has no attribute
  • TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
  • result is NaN

How to fix it

Check the result of anything that can fail to find something, before using it. Prefer ?? over || and `is None` over truthiness, because 0 and "" are falsy but not missing — that distinction is the source of a whole family of these. Work backwards from the crash to where the value was created; the bug is at the creation, not the crash.

Practise null and undefined errors

Working code with one bug in it. Find it, fix it in the browser, and see the explanation. No account needed.

pythonEasy
Missing config key crashes the lookup

get_setting(config, key) should return the value for a key, or the string "default" when that key isn't present.

Null / Undefined

javascriptEasy
First item's name crashes on an empty list

firstItemName(items) should return the name of the first item, or "None" when the list is empty.

Null / Undefined

javascriptEasy
Null check missing before property access

getUserCity(user) should return the user's city, or "Unknown" if the user has no address on file.

Null / Undefined

javascriptHard
Optional chaining only guards the first link

cityOf(user) should return the user's city, or "unknown" if any part of the path is missing.

Null / Undefined

javascriptHard
Destructuring default ignores an explicit null

greet(user) should greet the user by name, falling back to "guest" when no name is available.

Null / Undefined

pythonHard
next() explodes when nothing matches

first_match(items, target) should return the first matching item, or -1 when there is no match.

Null / Undefined

pythonHard
A reading of zero counts as no reading

describe_temp(readings, station) should report 'recorded' whenever that station reported a temperature — including a reading of 0 degrees — and 'missing' only when the station is absent.

Null / Undefined

pythonMedium
Missing score turns the total into a crash

total_score(scores, names) should add up the scores for the named players, treating anyone without a score as 0.

Null / Undefined

javascriptMedium
find() result used without checking

priceOf(items, name) should return the named item's price, or 0 when there is no such item.

Null / Undefined

javascriptMedium
Total score comes out as NaN

sumScores(players) should add up every player's score, treating a player with no score as 0.

Null / Undefined

pythonMedium
Zero retries becomes three retries

retries_for(config) should use config['retries'] when present and default to 3 when it is missing. A value of 0 means 'do not retry'.

Null / Undefined

javascriptMedium
A setting of zero falls back to the default

retriesFor(settings) should use settings.retries when it is provided and fall back to 3 when it is missing. Setting retries to 0 means 'do not retry'.

Null / Undefined

pythonMedium
Optional middle name breaks the full name

full_name(user) should join a user's name parts with single spaces, skipping the middle name when there isn't one.

Null / Undefined

Other bug patterns