Debugging Interview Questions

Debugging rounds test method over tooling — how you narrow an unfamiliar bug when you do not yet know anything about its cause.

This topic has 15 curated Debugging questions covering reproducing bugs, narrowing search space, observability, race conditions and logging. Below are 8 of them in full, with the same answers you get in the interactive tool.

Practise all 15 Debugging questions →

Difficulty breakdown

  • Easy1
  • Medium8
  • Hard5
  • Expert1

Question formats

  • Scenario4
  • Debugging3
  • Multiple choice3
  • Concept2
  • Best practice1
  • Code review1

What these questions cover

  • method
  • observability
  • tooling
  • error-tracking
  • errors
  • logging
  • production
  • race
  • state
  • testing

8 example Debugging interview questions

MediumBest practice

What has to be in your logs and error reports for a production bug to be diagnosable without a reproduction?

Enough context to reconstruct the moment: a release or commit identifier, so you know which code ran; a correlation id shared with the backend request; the user or session identity in a form you are permitted to store; the app state that mattered — route, feature flags, relevant ids — and a breadcrumb trail of the last several actions. Error objects need their `cause` chain preserved, and the stack has to be symbolicated against the right source map. What must not be in there is anything personal: form contents, tokens, or full request bodies.

The single highest-value item is the correlation id, because it turns "an error happened in the browser" into "here is the exact server request, its logs and its timing". The second is breadcrumbs — most frontend bugs are sequence-dependent, and a stack trace tells you where it broke but not what the user did to get there. Both have to be designed in; neither can be added after the bug report arrives, which is why this is a build-time decision rather than a debugging technique.

MediumCode review

Review this error handling from a debugging perspective

try {
  await submitOrder(cart);
} catch (e) {
  console.error('Order failed');
  showToast('Something went wrong');
}

Nothing here helps anyone diagnose the failure. The caught error is discarded entirely — no message, no stack, no cause — so the log line says a thing failed without saying why. There is no context (which order, which user, which attempt), no report to an error service so it is invisible unless someone is watching a console, and no distinction between failure types: a declined payment, a network drop and a validation error all produce the same opaque toast. Log the error object itself with structured context, report it, and branch the user-facing message on the failure kind so the toast tells the user whether to retry.

This exact shape is why production incidents so often begin with "we have no idea, the logs just say it failed".

EasyConcept

Describe how you narrow down an unfamiliar bug, before you know anything about the cause

Make it reproducible first — a bug you cannot trigger on demand cannot be verified as fixed. Then narrow the search space by halves rather than inspecting linearly: does it happen with a different user, a different browser, an empty dataset, the previous release? Each answer eliminates a category. Form one hypothesis at a time and test it specifically, rather than changing several things and seeing if the symptom moves, which teaches you nothing when it does. Read the actual error and the actual values rather than assuming — most of the time the message is accurate and the assumption is not. And write down what you have ruled out, because long investigations otherwise revisit the same ground.

Reproducibility first is what makes the rest possible — without it you cannot confirm a fix, only stop seeing the symptom. Halving the search space beats reading code linearly because each answer eliminates a whole category rather than one line. Changing several things at once is the habit to break: when the symptom disappears you no longer know which change did it, or whether you introduced a second bug that masks the first.

ExpertDebugging

The bug vanishes when devtools is open or when you add a breakpoint. What does that tell you?

// Intermittent: element is sometimes measured as 0 height.

Almost certainly a timing or ordering dependency. Opening devtools and pausing changes the timing enough to let a pending operation complete first — so the code is reading something before it is ready: measuring an element before layout or before fonts and images load, reading state before an effect has run, or depending on two async operations completing in a particular order. Debug without altering timing: add timestamped logging rather than breakpoints, record a performance trace, or force the suspected slow path with network and CPU throttling so the failure becomes reliable. Then fix the ordering explicitly — wait for the actual signal (ResizeObserver, `document.fonts.ready`, an await) rather than a timeout that happens to work.

The key discipline is switching to observation methods that do not perturb timing, because the debugger itself is changing the system.

MediumFollow-up

You found and fixed the bug. How do you convince yourself the fix is real?

Prove the mechanism, not just the symptom. Re-introduce the original condition and confirm the failure returns, then apply the fix and confirm it goes away — a fix you cannot make fail on demand may be coincidence, especially for timing bugs. Write a regression test that fails against the old code and passes against the new, and check that it fails for the right reason rather than for a setup error. Explain the causal chain from cause to symptom out loud; if any link is "and then somehow", the diagnosis is incomplete. Finally, look for sibling instances of the same mistake elsewhere in the codebase, because a bug that appeared once in a pattern usually appears more than once.

The "make it fail again" step is what separates a verified fix from a change that happened to coincide with the symptom disappearing.

MediumMultiple choice

Which breakpoint helps when you do not know WHERE a value is being changed?

When the symptom is "something set this and I do not know what", break on the CHANGE rather than a line: devtools can break on attribute or subtree modification, and a conditional breakpoint narrows a hot path to the one case you care about.

HardScenario

Your error tracker shows 40,000 events across 300 issues and no user has ever complained. How do you triage?

Stop treating events as the unit and rank by affected users, not occurrences — one user in a reconnect loop can generate thousands of events and means far less than an error hitting 200 people once each. Then split the list: errors you cause versus noise you do not. Extension-injected scripts, cross-origin "Script error." with no stack, network failures from users going offline, and aborted requests from navigation are all noise and should be filtered at the SDK, not triaged repeatedly. For what remains, correlate against a real signal — does this error coincide with a drop in conversion, a failed save, a support ticket? An error nobody notices may genuinely not matter, or it may be one that fails silently, and the correlation is what distinguishes them.

The silent-failure case is the one that justifies the whole exercise: a caught-and-swallowed error on a save path produces no complaint because the user does not know the save failed, and it is indistinguishable from harmless noise in a list sorted by count. Once triaged, the way to keep it that way is a budget rather than a cleanup — a threshold that fails the build or alerts on new issues, so the list cannot drift back to 300.

MediumConcept

When is bisecting better than forming a hypothesis, and vice versa?

Bisect when you have a reliable test for the failure and a known-good point in the past — it is mechanical, requires no understanding of the code, and finds the change in logarithmic time. It is the right tool for a regression in unfamiliar code. Form a hypothesis when the bug is not a regression (it never worked), when you cannot reliably answer "is it broken here", or when the change set is not the interesting variable — a data-dependent or environment-dependent bug will bisect to a commit that merely exposed it. The two combine well: bisect to narrow the surface, then reason about the specific change. The precondition for bisecting is always a deterministic check, which is why making the bug reproducible comes first either way.

The failure mode worth naming is bisecting an intermittent bug, which produces a confident but wrong answer.

The remaining 7 Debugging questions — plus mock interviews, spaced revision and progress tracking — are in the free interview prep workspace.

Related interview topics