Debug code

Read the stack trace

Start at the error message and first relevant application frame instead of reacting to the longest library path.

10 minute lesson

~~~

A stack trace shows the chain of calls present when an error was created. The bottom frame started everything; the top frame is closest to the failure. Most developers’ real mistake is not reading it at all — they see red text and start guessing.

Run a tiny failure:

function total(items) {
  return items.reduce((sum, item) => sum + item.price, 0)
}

total(undefined)

Node prints:

TypeError: Cannot read properties of undefined (reading 'reduce')
    at total (/srv/app/cart.mjs:2:16)
    at file:///srv/app/cart.mjs:5:1

Read it in this order. First the exception type and message: TypeError, something was undefined and we asked it for reduce. The message already names the broken value — the thing reduce was read from, so items. Then the first frame: total at cart.mjs line 2, where the error surfaced. Then the callers below it: line 5 is who passed undefined.

That means the fix belongs at the caller or at the function boundary, not on line 2. Fix the invalid caller or validate the function boundary rather than hiding the trace behind a try/catch that swallows it.

Library frames are noise, usually

In a real application the top frames often belong to a framework. The top frame is closest to the failure, but framework wrappers may appear before your code:

    at Array.reduce (<anonymous>)
    at total (/srv/app/cart.mjs:2:16)
    at handleCheckout (/srv/app/routes/checkout.mjs:14:20)
    at Layer.handle (/srv/app/node_modules/express/lib/router/layer.js:95:5)

Scan for the first frame in your own code: cart.mjs, then checkout.mjs. The node_modules frames explain how execution got there, not what went wrong. The longest, scariest path in the trace is almost never the interesting one — unless every frame is library code, which usually means you passed a library something invalid.

Do not return stack traces to public clients. They reveal file paths, dependency names, and internal structure. Keep the detail in protected logs, and send the client a generic error with a request ID that lets you find the full trace later.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →