# 13.8 When it breaks: reading an error (/building-ai-workers/programming-fundamentals/reading-an-error)

---
type: Document
title: "13.8 When it breaks: reading an error"
description: "How to read a Python traceback and a Node stack trace, find the first line in your own code, and name the cause in one sentence."
status: stable
order: 313.08
ksor:
  owner: team:panaversity
  audience: [ public ]
  approval:
    by: process:panaversity
    at: 2026-10-31T22:24:22Z
chapter: "13"
part: III
expert_status: builder-only
concepts: [ "13.8" ]
last_verified: 2026-10-30
generated:
  at: 2026-10-31T22:24:22Z
  by: process:panaversity
trust_tier: unverified
build_id: sha256:e1fbcb7d9a8f8b9b7cb96875022325c02c9ba4be94cef13b301cbd39a9edad85
dirty: true
ksor_version: 0.0.60
---

**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?

```text
$ 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.**

```text
$ 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. Two error reports with the lines that matter marked. In the Node report, read the message at the top, find where the error was raised in due-date.ts, and trace the bad value back from reconcile.ts line 16. In the Python report, read the KeyError on the last line first, then look upward to the failing line.](img/error-report.png)

*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](both-ai-vendors.md#practice-read-an-error), in your own tool, five minutes.
