1. Neti Neti
10:52
Text-to-speech. The essay is the script.
10 minutes 52 secondsYou are staring at a bug in a codebase you did not write. The stack trace is four levels deep in a library you have never heard of. The last person who touched this module left the company six months ago. You have no theory. You cannot form a hypothesis, because you do not know enough about the system to guess intelligently.
What do you do?
“Neti, Neti” is Sanskrit for “not this, not this.” The phrase comes from the Brihadaranyaka Upanishad. Brahman, the ultimate reality in Advaita Vedanta, is not any particular thing, so you cannot describe it directly. The only way to point at it is to say what it is not. The Katha Upanishad takes that abstract method and gives it a story.
Nachiketa, still a boy, watched his father give away his possessions in a ritual sacrifice meant to earn heavenly reward. He saw what the gifts actually were: old cows, barren, too weak to give milk. He saw the emptiness behind the ritual. He asked his father three times, “To whom will you give me?” Angry, the father snapped, “I give you to Death.”
So Nachiketa goes. He waits at Death’s door for three nights without food while Yama, the god of death, is away. When Yama returns, he is uneasy to have left a guest waiting unhonored, and offers three boons in return, one for each night.
The first boon: let my father welcome me home, free from anger. Granted. The second: teach me the fire-sacrifice that leads to heaven. Yama teaches it, and, pleased with the boy, names the rite after him.
Then Nachiketa asks his third question. Not wealth, not power, not long life. “When a person dies, some say they still exist, others say they don’t. Taught by you, I want to know.”
Yama refuses. “Even the gods once debated this. It is subtle. Choose something else.” Nachiketa will not move. “If the gods were uncertain, and you say it is hard, I’ll never find a teacher like you. No other boon equals this.”
So Yama tries a different way. He offers everything. Sons and grandsons who live a hundred years. Cattle, elephants, gold, horses. Kingdoms. Music and good company. Every desire a mortal could name. Only stop asking about death.
Nachiketa refuses again. “These things last until tomorrow, and they wear out the senses. Even a whole life is short. Keep your horses. Keep your dancing and singing. No one is made happy by wealth. Having seen you, what use are riches?”
Yama, out of offerings, finally teaches.
The shape of the story is the method. Each time Yama offers something, Nachiketa refuses, and each refusal narrows what is left. What remains when everything else is gone is the truth he came for.
Conventional debugging is taught as hypothesis-driven search. You form a theory about what is wrong. You test it. If you are right, you fix the bug. If you are wrong, you form a new theory.
This works when you know the system. Your theories have decent odds, because the architecture lives in your head: the data flow, the failure patterns, the places things usually break. You are debugging inside your own mental model.
It fails when you do not know the system. No mental model means no useful hypotheses. You guess, you guess wrong, you guess again, and each wrong guess costs time while the bug stays put. In an unfamiliar codebase, hypothesis-driven debugging is not a method, it is gambling.
The first hour in a system you did not build is always the same: a theory, a test, a wrong answer, repeat. The theories are fine. What traps you is trying to find the bug at all, when the move is to eliminate what is not the bug.
Linus Torvalds wrote the first version of Git in April 2005, and git bisect was there in the early days. The idea is binary search over history. The Linux kernel absorbs thousands of commits per release. When a regression lands, a driver that worked in one version and fails in the next, nobody reads the commits looking for the cause. You mark a known-good commit and a known-bad one. Git checks out the midpoint. You test, mark it good or bad, and Git halves the remaining range and checks out a new midpoint. After about thirteen steps you are at the exact commit. That is log base two of ten thousand. Thirteen tests to certainty.
At no point did you search for the bug. You searched for the boundary between working and broken. The commit at that boundary is the bug, and you did not find it. You eliminated everything else until it was the only thing left.
Git’s own README, written in that first 2005 commit, calls it “the stupid content tracker.” Linus meant the word. The tool knows nothing about your code, and git bisect knows even less. It does not know kernels, or drivers, or what your test proves. It halves a range and asks one question: good or bad? The tool that admits it knows nothing is the one that converges. The debugger who arrives with theories might not.
You can hand even the judgment to a script. git bisect run make checks out each midpoint, runs the build, and reads the exit code: zero is good, anything else is bad. Fourteen tests walk sixteen thousand commits down to the one that broke it, with no one watching. The method does not need someone who understands the code. It needs a test that can say “not this.”

You don’t find the bug by searching for the bug. You find it by eliminating everything it’s not.
Remember Yama’s offerings: wealth, power, long life. Those are the easy debugging theories. “It’s probably a cache issue.” “Maybe the network is slow.” “Check whether the database is down.” Every experienced debugger knows them. They come to mind first because they are obvious and easy to test, and in an unfamiliar system they are almost always wrong.
Yama is testing whether the boy actually wants the truth, not hiding it from him. If wealth distracts you, you did not really want to know what happens after death. If the cache theory satisfies you, you did not really want to find the bug. The debugger who can say “not the cache, not the network, not the database” and keep narrowing is Nachiketa at the terminal. The easy theories are a filter, not an obstacle. Refuse them and continue.
The method works for deterministic failures. Regressions, bisectable bugs, anything where you can define “good” and “bad” without ambiguity and trust the test to tell the truth.
Non-deterministic failures defeat it. A race condition that shows up one time in a thousand breaks it, because you cannot trust the test. You mark a commit “good,” but the bug was there and stayed silent. You mark another “bad,” but the failure was random. The signal is corrupted, and bisection converges on noise instead of the bug. Heisenbugs, failures that change behavior when you observe them, are worse. The test itself alters the outcome. You are not eliminating possibilities. You are creating them.
Binary search assumes a stable reality, and so does the Upanishadic method. When reality is not stable, when the system is too emergent or too concurrent to give a straight answer, you need other tools. Every method has limits. This one works anywhere you can say, reliably, “this is not it.”
The Linux kernel is where the method proves itself. A release regresses, someone reports it, and a maintainer bisects between the last good release and the first bad one. Thousands of commits collapse to one in a dozen or so tests. The person running the bisect often has no idea what the offending commit does until Git hands it over. They did not theorize the cause. Elimination found it. This is the standard way the kernel localizes regressions, not a one-off trick, documented in Git’s own manual and run every release cycle. git bisect run exists because the pattern is common enough to automate.
Nachiketa got his answer. Yama taught him the nature of the Self, the path beyond it, and what survives. That teaching fills the rest of the Katha Upanishad, and it is not this one.
This one is about the asking and the refusing. A boy stands at Death’s door, turns down every distraction on offer, and narrows the question until only the answer is left. The same shape runs under a command you already use. The next time you bisect a regression, you are doing what he did. Not finding the answer. Refusing everything that is not it.
Further Reading
The Katha Upanishad is available in many translations. Eknath Easwaran’s (Nilgiri Press, 1987) is the most readable in English. Swami Gambhirananda’s translation with Shankara’s commentary (Advaita Ashrama) is the one to reach for when you want the traditional reading. Robert Ernest Hume’s public-domain translation (Oxford, 1921) collects the principal Upanishads, including the Brihadaranyaka passage where “Neti, Neti” first appears. Swami Sarvapriyananda’s lecture series on the Katha Upanishad (Vedanta Society of New York) walks through the Nachiketa and Yama dialogue in depth and is freely available.