An interviewer who runs this debugging exercise has chosen real code over a puzzle on purpose. Most engineering time goes into code somebody else wrote, and most of that time is spent working out why it does not do what it should. The format samples that directly. It shows how you orient yourself in an unfamiliar codebase, whether you reach for tools or for intuition, and whether you can tell a real fault from code that is merely written differently from how you would write it.
It also tests restraint. You have forty-five minutes and an unknown number of breaks. Rewriting things that work is a cost, and the interviewer is watching whether you know that.
The questions to ask before reading
Each of these changes how you spend the forty-five minutes, which is why they come first.
| Question | Why it changes your plan |
|---|
| What should this code do, and is there a spec or example output? | Without a definition of correct, you will "fix" deliberate behaviour that looked odd to you |
| Can I run it, and can I use a debugger and print statements? | Running it turns a reading task into an observation task |
| Is there a test suite, and does it pass? | Failing tests are a map. A suite that passes tells you the breaks are where tests do not reach |
| How many breaks are there, or is that part of the test? | A known count tells you when to stop; an unknown one means you budget time per break |
| Is the goal to find, to fix, or to explain? | Finding every break beats fixing one well if finding is what is graded |
| Is the history available? | If a diff exists, ask whether you may use it. Usually not, but asking shows you would |
None of these are stalling. They take two minutes and they are the questions you would ask a colleague who handed you a broken service. The interviewer may decline some of them, and that is information too.
Let behaviour point you to the code
Once you can run it, reproduce a failure and trace it backwards. Take an input that gives the wrong output, find the last point where the data is still correct, and narrow from there. That is a binary search over the execution path, and it finds a planted change in a function you would never have suspected.
Code reading still has a place in a debugging exercise, but a targeted one. Skim for structure first: entry points, the main data flow, which modules call which. Then read closely only where the trace has led you. Two hundred lines read carefully in the right place beat two thousand read evenly.
When there are no tests, write two kinds. A test asserting the correct output for an input that currently fails gives you a way to confirm a fix. A characterisation test pinning the current output of a path that already works tells you when a fix, or a second fix, changes something it should not have.
Why the worst-looking line is usually innocent
The tweaks are made by someone who knows you will be reading for them. So they are small: a < that became <=, a negated condition, two swapped arguments of the same type, a removed null check, a constant changed from 1000 to 100. These are the same changes mutation-testing tools generate on purpose — boundary shifts, negated conditionals, altered return values — because they are the changes that compile, look reasonable and change behaviour.
Meanwhile, production code is full of things that look wrong and are not: an odd retry loop with a comment about a vendor, a special case for one customer, a hand-rolled date function that predates the library. A candidate reading for suspicion spends their time on those, because they look most like bugs. The planted change, which looks like ordinary code, gets read past. Strong candidates find breaks through failing inputs and treat odd-looking code as presumed deliberate until a trace says otherwise.
Treating it as a puzzle to solve by inspection
A candidate who has only practised LeetCode treats it as a puzzle to be solved by inspection, so code reading becomes the whole method instead of one tool. They start at the top, read every line, and form theories from what looks unusual. They rarely run the code, because in an algorithm round running the code is the last step rather than the first.
They also stop too early. Having found one break, they fix it and announce they are done, without re-running anything to see whether the failure has gone or whether a second one is now exposed. And they "improve" code along the way, renaming and restructuring as they read. That turns a debugging exercise into a diff the interviewer has to review, and occasionally introduces a fourth break.
Spending the forty-five minutes
A reasonable shape is five minutes on questions and getting it running, five on structure, then about ten minutes per break with a test confirming each fix. Keep the last few minutes to summarise what you found, what you fixed, what you would check next, and where you are still unsure. Say the budget out loud at the start. If one break is taking twenty minutes, say so and move on. Unless you were told that fixing is what counts, three found and one fixed shows more than one fixed beautifully and two never looked for.
Planted breaks are designed to survive reading. Get the code running, find an input that fails, and let the failure tell you where to look.
© 2026 Preptima. Originally published at preptima.com (opens in a new tab).