13.8 When it breaks: reading an error
- Approved by
- Panaversity ·
In everyday life. When a car's dashboard light comes on, "the car is broken" does not help the mechanic. "The oil light came on at highway speed, and the engine was hot" does. The light is not the problem. It is a message, and reading it well saves hours of work.
What you will learn. How to read what a program prints when it fails, and name the cause in one sentence.
Why it matters. When a program breaks, it tells you what went wrong and where. Read it, and tell the agent exactly what broke.
When a program fails, it prints an error report. TypeScript under Node calls it a stack trace. Python calls it a traceback. Both say the same three things: what kind of error it was, its message, and the chain of function calls that led to the line where it happened. A function calls another when it uses it. That chain is called the call stack.
Where do I start reading an error?
At the bottom for Python, and at the top for Node, because the two languages print the chain in opposite orders. Python tells it like a story: the ending, what went wrong, comes last. Node tells it like a news report: the headline first.
| Python traceback | Node stack trace | |
|---|---|---|
| Where the error name and message are | The last line | Near the top, under a copy of the line that failed |
| Order of the calls | Oldest first, the failing line last | The failing line first, then the lines that called it |
| Where to start | Read from the bottom up | Read the message, then down to the first line in your own files |
In both, skip the lines that point into the language itself, such as node:internal and <frozen runpy>. Then find the first line in a file you own.
Which errors will I meet most?
| Error | Usually means | What to tell the agent |
|---|---|---|
Module not found (ERR_MODULE_NOT_FOUND, ModuleNotFoundError) | A file or a package, a group of modules published under one name, is missing, or the import path is wrong | "This import points to a file that does not exist" |
Type or value error (TypeError, ValueError) | A value is the wrong type, often text where a number belongs, or text that cannot be converted | "The amount arrives as text. Convert it when the row is read" |
Missing key (undefined, KeyError) | A record has no value under that key | "The file has no terms column" |
File not found (ENOENT, FileNotFoundError) | The path is wrong, or the program ran from another folder | "It runs from py/, so the path needs ../data/" |
| Your own error | The code found a problem on purpose | Read its message. It was written for you |
"It broke" versus a precise description. The most expensive habit with a coding agent is saying "it failed, fix it" without reading the error. Like a mechanic asked only to turn the oil light off, the agent may hide the error instead of fixing its cause, for example by giving every row with no terms "Net 30". Your job is to read the error and name it.
Why is the failing line not always the bug?
A program raises an error, stopping to report it, at the line where a bad value finally causes trouble. The bug is often earlier, where the bad value came from. It is like a payment the bank sends back: it failed at the bank, but the mistake was made earlier, when someone typed the vendor's account number. Follow the chain back to the first place in your own code that passed it along.
At work. Ana has the agent run the reconciliation script, which checks each stated due date against the terms, on a file whose terms column is missing. Both languages fail. TypeScript reports "Unknown terms: undefined" in due-date.ts. Python names the cause directly: KeyError: 'terms', in reconcile.py.
In TypeScript. Predict: which line in your own code did the bad value come from?
$ npm run reconcile -- data/invoices-no-terms.csv
file:///.../src/due-date.ts:13
throw new Error(`Unknown terms: ${terms}`);
^
Error: Unknown terms: undefined
at termsDays (file:///.../src/due-date.ts:13:11)
at dueDate (file:///.../src/due-date.ts:22:39)
at reconcile (file:///.../src/reconcile.ts:16:22)
at file:///.../src/reconcile.ts:26:17
at ModuleJob.run (node:internal/modules/esm/module_job:439:25)The message is at the top. The first lines are in due-date.ts, which raised the error on purpose, with throw. The bug is one step further down, at reconcile.ts:16, the caller that passed undefined.
In Python.
$ uv run python -m brightline_ap.reconcile ../data/invoices-no-terms.csv
Traceback (most recent call last):
File "<frozen runpy>", line 88, in _run_code
File ".../py/brightline_ap/reconcile.py", line 31, in <module>
found = reconcile(Path(file).read_text(encoding="utf-8"))
File ".../py/brightline_ap/reconcile.py", line 21, in reconcile
computed = due_date(row["invoice_date"], row["terms"])
~~~^^^^^^^^^
KeyError: 'terms'The message is at the bottom. Just above it, Python marks the exact expression, row["terms"].
Ana's sentence. "The error is raised in due-date.ts, but the cause is reconcile.ts line 16: this file has no terms column, so the terms it passes are undefined." Then she asks: "Please make the script stop with a clear message that names the missing column. Don't fill in default terms."
Where the languages differ. A missing key in TypeScript gives undefined, which is passed along until something else fails, so the error appears far from the cause. Python raises KeyError at the lookup itself. That is one more reason why the type checker and tests matter more in TypeScript. The language does not stop you early.
The operating rule: read the error before you ask for a fix, find the first line in your own code, follow the bad value back to where it came from, and name the file, the line and the cause in one sentence.

Figure 13.11. Reading an error report. In Python start at the bottom, in Node start at the top, and in both find the first line in a file you own, then follow the bad value back.
Practice it. Practice: read an error, in your own tool, five minutes.
Check yourself
Question 1 / 8
0 answered
An agent's script stops with this traceback.Traceback (most recent call last):
File ".../py/brightline_ap/load_amounts.py", line 4, in <module>
total += int(row["amount"])
~~~^^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: '1,250.00'What is the cause?
- Owner
- Panaversity