Minimal Reproductions and Diagnostic Evidence
A minimal reproduction is a small, self-contained way to demonstrate a specific failure. The goal is to preserve the meaningful symptom while removing unrelated complexity, not simply to produce the shortest program.
Write the failure predicate first: expected result, actual result, and the conditions that distinguish this problem from another one. Then reduce in controlled steps and rerun that predicate. Package enough environment and execution evidence for another person to reproduce the result without inheriting your whole workspace.
TL;DR
- A minimal reproduction is a small, self-contained demonstration of one specific failure.
- Write the failure predicate first: expected result, actual result, and the conditions that distinguish this problem.
- Reduce in controlled steps and rerun the predicate each time, so you keep the original symptom.
- Package enough environment detail — versions, inputs, commands — for someone else to reproduce it.
- Remove private data, then rerun the predicate to confirm the failure survives.
Quick Example
This fictional Python defect sums values after converting rows into a dictionary, which overwrites earlier values with the same identifier. The reducer removes one row at a time only when the numerical mismatch remains. It is an illustration of preserving a failure, not a real customer incident.
The reduced case retains two duplicate-identifier rows: expected sum 10, actual sum 7. Removing either remaining row loses this failure. The same reducer should leave an already-minimal case unchanged and reject an input that never failed.
The result is minimal for single-element removal under this predicate. It is not proof of the globally smallest example, the cause of an unrelated incident, or preservation of concurrency and timing. No issue was submitted and no private source or production data was used.
Core Concepts
Define the same failure before reducing
An exception type, exit status, wrong result, deadlock condition, or diagnostic can form part of a predicate. Choose enough detail to reject unrelated failures. A reduction that replaces a data corruption symptom with an import error is smaller, but it no longer demonstrates the original problem.
GCC's minimization guidance recommends a self-contained test case and describes direct construction or iterative reduction, checking after each change that the bug remains evident. Its compiler-specific instructions are useful context, not a requirement that every application report use preprocessed C or C++. GCC minimization guidance.
For a numerical defect, preserve the expected and actual values or their meaningful relation. For a crash, retain the relevant operation and failure signature. For an intermittent issue, define the repetition procedure and observation criteria rather than promising that a single passing run establishes anything.
Small and self-contained are related goals
Remove irrelevant data, modules, configuration and dependencies while keeping the requirements that trigger the defect. The smallest file may still depend on an undocumented database state, local path, environment variable, or service. A slightly larger fixture that creates its own state can be far easier to reproduce.
Prefer synthetic data that preserves the relevant structure. Replacing a private record with harmless text is useful only if the defect still occurs and the replacement does not disclose another sensitive detail. Review the finished package itself; deleting one obvious secret does not establish that logs, paths and configuration are safe to share.
Reduction is an experiment, not a verdict
Removing a component while preserving the symptom shows that the component is unnecessary for this reproduction. It does not establish that the component is irrelevant to every occurrence of the incident. Similarly, making the symptom disappear after changing two factors does not identify which change mattered.
Retain checkpoints so unsuccessful reductions can be reversed. The GCC guide explicitly calls for restoring the previous failing version when a simplification loses the bug. Apply that experimental discipline to configuration and data as well as source code. GCC iterative reduction.
Record changes to the environment during the investigation. A dependency update, different optimization level, warmed cache, or reset service can alter the symptom independently of the source reduction. Keep the final recipe aligned with the environment that actually produced the retained evidence.
Best Practices
Begin with a compact evidence note
Write the intended task, exact symptom, first known relevant version, platform, and a short run recipe. Separate observations from hypotheses. A report can say that a duplicate identifier changes the total without claiming that the same mechanism explains an unobserved production failure.
Keep diagnostics focused on the operation identity and failure boundary. Include enough surrounding context to interpret the record, but avoid copying an entire environment dump that may contain secrets. Retain full local evidence according to the organization's policy when needed; share the deliberately reviewed subset.
Reduce one dimension at a time
Try smaller input, fewer modules, a simpler setup, and fewer dependencies. Rerun the same predicate after each accepted change. If a change modifies the failure class or removes the relevant condition, restore the checkpoint and choose another reduction.
The example's greedy one-row approach is deliberately limited. Other removal orders or transformations can produce different small cases. Label the achieved form of minimality rather than claiming an optimal reduction algorithm from one result.
Verify from a fresh starting point
Follow the final recipe in a new local folder or appropriately isolated environment. Confirm that the package contains its inputs and instructions and does not depend on an unexplained cache or existing process. Record the actual versions used for this check.
If the defect is intermittent, retain the observed number of attempts, failures, workload and timing conditions. A reduction that removes the concurrency responsible for a fault may become perfectly reliable while preserving none of the problem. Use a predicate and experimental design suited to that uncertainty.
Keep the fix tied to the original requirement
After identifying a candidate correction, rerun both the reduced case and representative application checks. A narrow fixture can clarify a mechanism while omitting constraints of the full system. Verify that the correction preserves required behavior and does not merely suppress the diagnostic or skip the work.
Common Mistakes
Reducing until a different error appears
Sending a whole project without a recipe
Assuming synthetic data is sanitized
Claiming the smallest possible case
FAQ
Must a reproduction be very short?
It should remove irrelevant complexity while remaining self-contained and faithful to the failure. A modest fixture with explicit setup can be more useful than a tiny snippet that depends on hidden state.
Does preserving a failure prove its root cause?
No. It supplies evidence and narrows the investigation. A causal conclusion needs an explanation and experiments that distinguish competing hypotheses, followed by validation of the correction.
What should accompany the code?
Relevant versions and platform, setup and execution steps, minimal inputs, expected and actual results, focused diagnostics, and known repeatability limits. Review the package for sensitive material before sharing it.