skip to content

How do you cut a defect down to a minimal reproduction before filing it?

level: middleimportance: should knowfreq 55%

answer

  1. Smaller is not the goal
  2. Change one thing, then re-run
  3. Stop when nothing else can go
  4. Same symptom, not merely still failing
  5. Volume can be load-bearing

basics

~20 s

Remove or simplify one factor at a time - steps, data, flags, concurrency - resetting and re-running after each change. Keep removals that still fail, restore the ones that stop it, and finish when nothing else can go.

solid answer

~40 s

Minimal means irreducible, not short: the target is a case where removing any remaining factor makes the failure stop. Capture the original path first, then attack one category at a time - steps, input data, account state, configuration flags, concurrency, client, time - changing exactly one thing per run and resetting state between runs. When many independent factors are in play, halve rather than iterate: drop half the data, re-run, keep the failing half. After each removal, verify it is still the *same* symptom, or you have quietly minimised into a different defect. Some factors are load-bearing and must stay, including volume. Time-box the effort; an unminimised report filed early with full evidence beats a perfect one filed after the branch cut.

code

pseudocode · 14 lines
pseudocode
steps = recordedSteps
while true:
    removable = NONE
    for i in indices(steps):
        candidate = steps without steps[i]
        resetEnvironment()
        result = run(candidate)
        if result.failed and result.symptom == originalSymptom:
            removable = i
            break
    if removable == NONE:
        break
    steps = steps without steps[removable]
file(steps, loadBearing = originalSteps minus steps)

go deeper

for a junior

Know what a minimal reproduction is and that you reach one by removing things one at a time and re-running, not by rewriting the steps from memory afterwards.

for a middle

Explain the procedure and the halving shortcut, why you reset state between attempts, and why minimal means irreducible rather than brief.

for a senior

Demonstrate the traps: minimising into a different failure, volume or dirty state that is genuinely load-bearing, and time-boxing the effort so the report still lands inside the release window.

for a principal

Argue where the effort belongs - how much a reporter should minimise before filing versus what the owning team does with better instrumentation - and what that split costs in cycle time and in duplicate investigation.

## What "minimal" means A minimal reproduction is the smallest set of steps, data and configuration that still produces the failure, where smallest means **irreducible**, not short. The test is mechanical: remove any remaining factor and the failure must stop. Minimal is not the same as brief, and it is not the same as convenient - a failure that only appears once a queue holds two thousand items has a minimal reproduction that still holds two thousand items. ## Why bother Three payoffs. Diagnosis: every factor you removed is a hypothesis eliminated for free, so whoever fixes it starts from a narrower search space. Communication: a four-step case is executed the same way by everyone, while a 47-step manual path is executed differently by everyone and manufactures false "could not reproduce" outcomes. Durability: a minimal case is the natural seed for an automated regression case, because its incidental setup has already been stripped out. ## The procedure Work one change at a time and re-run after each change. Record the original path verbatim first, so you can always get back to it. Then remove or simplify exactly one factor, reset the environment, and run again. If it still fails, keep the removal. If it passes, put the factor back and mark it as load-bearing. Repeat until nothing else can go. With many independent factors - steps, form fields, records, flags - halving beats one-at-a-time. Drop half the data, re-run, keep the half that still fails, repeat. This halving strategy is the core of the technique published as delta debugging, and it turns a forty-item search into roughly six runs instead of forty. Attack these categories in turn: steps, input data, account and entitlement state, configuration flags, concurrency, client and tier, and time. Reset between runs. A case that only reproduces on the second attempt against dirty state is telling you the dirty state is part of the reproduction, and it belongs in the preconditions rather than being lost. ## Confirming the result After minimising, confirm the minimal case still fails from the stated build on a clean environment with fresh data, and if it is cheap, have someone who is not you run it. A minimal case that only fails on your machine has not been minimised; it has merely been narrowed down to something you have not identified yet. ## Where minimisation goes wrong **Minimising into a different defect.** You strip a data condition, still see an error, and file that - but it is a different error with a different cause, and the original stays in the field. The guard is cheap: after every removal, check that the symptom is still the *same* symptom - same message or code, same place in the flow, same side effect - not merely "still fails". **Load-bearing volume.** Take the nightly accrual job on a loyalty-points ledger that aborts at member 1,873 with the connection pool at its ceiling of 24. Cutting the member count makes it pass below about 1,800, so a naive minimiser concludes "not reproducible with 5 members" and files nothing. The correct minimisation keeps the volume and strips everything else: no user interface, no scheduler, drive the accrual entry point directly against two thousand identical synthetic members with one flag set. That case is three lines of setup and one action, and it is minimal even though it processes two thousand records. **Ignoring the clock.** Minimisation competes with filing. On a 3-week release train, an unminimised report filed on day 2 with complete evidence beats a perfect report filed on day 11 after the branch cut. Time-box the effort - an hour is a reasonable box - then file what you have, state plainly what you did and did not manage to eliminate, and keep going in the comments. ## What to write down besides the steps The minimal case is not the only output of the exercise. Record what you removed that surprisingly did *not* matter, because that rules out components for the reader. Record what you removed that made the failure vanish, because those load-bearing factors are the strongest signal you have about the cause. And keep the original path if it differs materially, since that is the route a real user took and it may carry impact information the minimal case throws away.

  • How do you know you have minimised into the same defect and not a different one?
    Compare the symptom, not just the outcome: the same message or code, the same point in the flow, the same observable side effect, and where possible the same trace shape. If any of those shift after a removal, that removal changed the defect. Put the factor back, keep the original reproduction, and treat the newly surfaced failure as a separate report if it is real. "Still fails" is not the check; "still fails the same way" is.
  • When is it right to file without minimising at all?
    When the failure is rare, destructive, or bound to state you may lose; when a deadline such as a branch cut is close; or when minimising needs access or data you do not have. File everything you captured, mark clearly that the case is unminimised, and list which factors you did manage to eliminate so the next person does not repeat that work. A prompt report with honest gaps is worth more than a perfect one that arrives after the release.

It is the same move as bisecting a broken circuit: you keep pulling components until the fault clears, and the last thing you pulled is where you look.

saying these in an interview costs you the question

  • Thinks minimal means short rather than irreducible
  • Removes several factors at once and cannot say which mattered
  • Never re-runs after a removal to confirm it still fails
  • Keeps cutting until a different, easier failure appears
  • Refuses to file anything until the case is perfect
  • Drops the volume that the failure actually depends on

context