Crux Read a stack trace and short snippets, then classify each failure: which line threw, whether it is a defined error or undefined behaviour, and where the real cause lives.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at middle altitude — in the sky
◷ 14 min
A failure is read in two places: the code that ran and the trace the runtime printed. For each snippet below, do what a working engineer does first — locate the throw site, name the kind of failure, and decide where the real cause lives.
Goal
Practise the reading loop the unit built toward: parse a stack trace top-down to find the throw site, classify a failure as a defined error or undefined behaviour, and separate where an exception surfaced from where its cause actually sits.
Snippet 1 — read the trace
Error: Cannot read properties of undefined (reading 'name') at formatLabel (render.ts:14) at renderRow (render.ts:31) at renderTable (render.ts:48) at main (app.ts:9)
Quiz
Completed
Reading this trace top-down, which statement is correct?
Heads-up The bottom line is the program entry — it is in nearly every trace and is almost never the cause. The throw site is the top line, formatLabel at render.ts:14.
Heads-up A trace is not the file's function list. It is only the frames active on the call stack at the throw — the chain main to renderTable to renderRow to formatLabel.
Heads-up The throw site is always the top line. renderRow appears below formatLabel, meaning renderRow was waiting at line 31 on its call to formatLabel — it did not throw.
Snippet 2 — classify the failure
function loadUser(record) { return record.profile.name.toUpperCase();}loadUser({ profile: null }); // profile is null, not an object
Quiz
Completed
record.profile is null, so the code reads .name from null. What kind of failure is this in JavaScript, and how will you find out about it?
Heads-up Reading a property of null is a defined error in JavaScript: it raises an exception. Undefined behaviour is the silent case with no error raised — this is the loud, reported case.
Heads-up null.name does not return undefined; reading a property of null raises a TypeError. (Reading a missing property of an object would give undefined, but null is not an object.)
Heads-up It is deterministic and defined: the same null read always raises the same exception. There is no garbage-bits outcome in a language that checks this case.
Snippet 3 — out of bounds, two languages
prices = [10, 20, 30] // valid indices 0, 1, 2read prices[5] // index 5 — two past the end
Quiz
Completed
The same out-of-range read runs in a bounds-checked language and in a low-level unchecked language. How do the two outcomes differ?
Heads-up Only the bounds-checked language raises an exception. The unchecked low-level language does no check — it reads the out-of-range cell and returns garbage with no error at all.
Heads-up undefined is JavaScript's specific defined result. A low-level unchecked language has no such guarantee — it reads whatever bits sit at the computed address.
Heads-up The index not being valid is the whole point. The bounds-checked language detects that and throws; the unchecked one ignores it and reads memory it should not.
Snippet 4 — throw site is not the cause
function parseAge(text) { const n = Number(text); if (Number.isNaN(n)) throw new Error("not a number: " + text); return n;}function loadProfile(raw) { return { age: parseAge(raw.age) }; // raw.age came from upstream}// raw.age is "thirty" — never validated before reaching here
Quiz
Completed
The trace tops out at parseAge ('not a number: thirty'). A debugging hypothesis must separate where the error surfaced from where the cause lives. Which reading is right?
Heads-up parseAge is doing its job: detecting bad input and reporting it loudly. Removing the throw would turn a loud, defined failure into a silent one — the worse outcome. The defect is the unvalidated 'thirty' upstream.
Heads-up The top line is where the error surfaced, not always where the cause lives. Here a caller passed bad data; reasoning follows the chain to the upstream step where state first went wrong.
Heads-up Throwing on bad input is correct behaviour, but the bad input itself is the defect. The unit's point is to keep reasoning past the throw site to the step that first diverged.
Recap
Every failure is read in code and trace: a trace is parsed top-down, the top line is the throw site and the bottom is just the entry; a property read on null is a defined error that raises loudly, while an unchecked out-of-bounds read is undefined behaviour that returns garbage silently; and the throw site is where the error surfaced, not always where the cause lives. Classify the failure, locate where it surfaced, then reason down the chain to the step that first went wrong.