User Guide

A comprehensive, hands-on guide to designing, running, and analyzing experiments with the DOE Helper Tool.

1 Getting Started

What is DOE Helper?

DOE Helper is a command-line tool that brings the power of Design of Experiments (DOE) to software engineers, data scientists, researchers, and anyone who needs to systematically optimize a process. Instead of changing one variable at a time (OVAT) or running random guesses, DOE lets you test multiple factors simultaneously in a structured way that reveals not just which factors matter, but how they interact.

What problems does it solve?

Tuning database configurations, optimizing compiler flags, finding the best ML hyperparameters, improving chemical processes, calibrating manufacturing settings — any scenario where you have multiple knobs to turn and want to find the best combination efficiently.

Installation

Terminal
$ pip install doehelper $ doe --version

For detailed system requirements and dependency information, see the Quick Start page.

Your First Experiment: End-to-End Walkthrough

Let's walk through a complete experiment from scratch. We'll optimize a web server's performance by testing three configuration parameters.

Step 1: Create a configuration file

Terminal
# Bootstrap a config with doe init $ doe init --name "Web Server Tuning" --factors 3 --operation full_factorial

Edit the generated config.json to define your factors and responses:

config.json
{ "metadata": { "name": "Web Server Tuning", "description": "Optimize Nginx for throughput and latency" }, "factors": [ {"name": "worker_connections", "levels": ["512", "2048"], "type": "continuous"}, {"name": "keepalive_timeout", "levels": ["15", "75"], "type": "continuous", "unit": "s"}, {"name": "gzip_level", "levels": ["1", "6"], "type": "continuous"} ], "responses": [ {"name": "throughput", "optimize": "maximize", "unit": "req/s"}, {"name": "p99_latency", "optimize": "minimize", "unit": "ms"} ], "runner": { "arg_style": "double-dash", "result_file": "json" }, "settings": { "operation": "full_factorial", "test_script": "benchmark.sh", "out_directory": "results" } }

Step 2: Preview and generate the design

Terminal
# Preview the design matrix $ doe generate --config config.json --dry-run # Generate the runner script $ doe generate --config config.json --seed 42 # Check the plan $ doe info --config config.json

Step 3: Run the experiment

Terminal
# Execute all runs $ bash run_experiments.sh # Check progress $ doe status --config config.json

Step 4: Analyze results

Terminal
$ doe analyze --config config.json

Step 5: Find the optimum

Terminal
$ doe optimize --config config.json --multi

Step 6: Generate a shareable report

Terminal
$ doe report --config config.json --output webserver_report.html

That's the full loop

In six commands, you went from a question ("which settings matter?") to a statistically rigorous answer with optimization recommendations and a shareable report. The rest of this guide dives deep into each step.

2 Core Workflow

Every DOE experiment follows the same six-phase lifecycle. The DOE Helper Tool provides commands for each phase.

Plandoe init / doe info
Designdoe generate
Executebash run_*.sh
Analyzedoe analyze
Optimizedoe optimize
Reportdoe report
PhaseCommand(s)What Happens
Plan doe init, doe info, doe power Define factors, responses, and choose a design. Verify the plan makes sense and has sufficient power.
Design doe generate Create the design matrix and generate a runner script. Use --dry-run to preview first.
Execute bash run_*.sh, doe record, doe status Run the generated script or manually record results. Track progress with doe status.
Analyze doe analyze Compute ANOVA, effects, generate plots, and identify significant factors.
Optimize doe optimize Find the best factor settings using response surface methodology.
Report doe report Generate a self-contained HTML report with all results, plots, and recommendations.

Iterative by nature

DOE is often iterative. After your first analysis, you may want to augment the design with center or star points, run additional blocks, or switch to a more focused design. The tool supports this workflow with doe augment and doe next-batch.

3 Working with Configurations

The configuration file (config.json) is the single source of truth for your experiment. Every command reads from it. Understanding its structure is essential.

Anatomy of a Config File

A config file has five top-level sections:

metadata

Human-readable name and description. Used in reports and status output. Optional but highly recommended.

factors

The variables you are testing. Each factor has a name, levels (at least 2), and an optional type and unit. This is the heart of your experiment design.

responses

What you are measuring. Each response has a name, optimization direction (maximize or minimize), and optional unit, weight, and bounds for multi-objective optimization.

runner

How factors are passed to your test script and how results are collected. Controls argument style and result file format.

settings

Design type, test script path, output directories, blocking, and design-specific options like LHS sample count.

Factor Types

Choosing the right factor type affects which designs are available and how results are analyzed.

TypeWhen to UseExamplesDesign Implications
continuous Numeric values on a scale Temperature (150–200), Pressure (2–6), Thread count (1–16) Required for CCD, Box-Behnken, and star points. Enables response surface modeling and interpolation.
categorical Discrete, unordered choices Algorithm (A, B, C), Cache type (LRU, LFU), Material (steel, aluminum) Works with all designs. Cannot be interpolated. No star/center points for this factor.
ordinal Ordered categories Priority (low, medium, high), Compression level (none, fast, best) Treated as categorical in most designs but ordering is preserved in analysis output.

Response Configuration

config.json — responses section
"responses": [ { "name": "throughput", "optimize": "maximize", "unit": "req/s", "weight": 2, // twice as important in --multi mode "bounds": [1000, 5000] // [worst, best] for desirability }, { "name": "p99_latency", "optimize": "minimize", "unit": "ms", "weight": 1, "bounds": [500, 10] // [worst, best] — note: worst > best for minimize } ]

Bounds direction matters

For maximize responses, bounds are [worst, best] where worst < best. For minimize responses, bounds are [worst, best] where worst > best. If omitted, bounds are auto-computed from observed data.

Fixed Factors

Fixed factors are held constant across all runs. They are passed to your test script alongside the varying factors but do not contribute to the design matrix.

config.json — fixed factors
"fixed_factors": { "duration": "60", "warmup": "10", "num_clients": "100" }

Use fixed factors when a parameter must be specified for your test script to run but you are not currently varying it. They appear in reports for reproducibility.

Runner Configuration

Argument Styles Explained

The arg_style setting controls how factor values are passed to your test script:

StyleInvocation ExampleBest For
double-dash ./test.sh --temperature 200 --pressure 6 --out run_1.json Most scripts. Clear, self-documenting, order-independent.
env TEMPERATURE=200 PRESSURE=6 OUT=run_1.json ./test.sh Docker containers, Makefiles, scripts that read environment variables.
positional ./test.sh 200 6 run_1.json Simple scripts. Order must match factor definition order.
Result File Formats

The result_file setting controls the expected output format:

json (default) — Your script writes a JSON file with keys matching response names:

run_1.json
{"throughput": 3420, "p99_latency": 47.2}

Quick Start with Templates

Use doe init to generate a starter config file rather than writing one from scratch:

Terminal
$ doe init --name "My Experiment" --factors 4 --operation plackett_burman # Creates config.json with 4 placeholder factors and sensible defaults

4 Choosing a Design

The right design depends on your goals, the number of factors, and how many runs you can afford. This section helps you make that choice.

Decision Guide

Quick rule of thumb

Screening (many factors, limited budget): Use Plackett-Burman or Definitive Screening to find the important factors. Optimization (few factors, need the best settings): Use Central Composite or Box-Behnken to model the response surface.

Design Comparison

DesignFactorsRuns (k factors)Detects InteractionsDetects CurvatureBest For
Full Factorial2–52k (e.g., 8, 16, 32)AllNo (2-level)Complete understanding of a small system
Fractional Factorial4–82k-1 or 2k-2Some (aliased)NoModerate screening with fewer runs
Plackett-Burman4–23k+1 (next multiple of 4)NoNoFast screening of many factors
Definitive Screening3–122k+1SomeYesModern screening: fewer runs, detects curvature
Central Composite (CCD)2–62k + 2k + ncAll (2FI)Yes (quadratic)Full response surface modeling
Box-Behnken3–7Varies (e.g., 15 for 3)All (2FI)Yes (quadratic)RSM without extreme corners
Taguchi2–15L4, L8, L12, L16, L27LimitedNoRobust design, signal-to-noise ratios
Latin Hypercube (LHS)AnyUser-definedVia analysisVia analysisSpace-filling, computer experiments
D-OptimalAnyUser-definedDepends on modelDepends on modelCustom run count, irregular constraints
Mixture (Simplex)3+VariesVia modelVia modelComponents that sum to 1 (formulations)

Screening vs. Optimization

DOE typically follows a two-phase approach:

PhaseGoalTypical DesignsResult
Phase 1: Screening Identify the vital few factors from a larger set Plackett-Burman, Definitive Screening, Fractional Factorial Narrow from 8–15 factors down to 3–5 important ones
Phase 2: Optimization Find the best settings for the important factors CCD, Box-Behnken, Full Factorial Response surface model with optimal settings

Run Count Reference

Use this table to estimate how many runs your experiment will require:

FactorsFull Factorial (2-level)Fractional (Res IV)Plackett-BurmanDefinitive ScreeningCCDBox-Behnken
38472015
4168893027
532168113246
6641681352
7128168157862
8256161217
101024321221
1532768641631

Design Evaluation Metrics

When you run doe info --config config.json, the tool reports three efficiency metrics:

MetricWhat It MeasuresGood ValuePractical Meaning
D-efficiency Overall information content of the design > 90% Higher means more precise estimates of all effects. An efficiency of 100% means the design is optimal for the given model.
A-efficiency Average precision of effect estimates > 80% Focuses on average variance rather than overall determinant. Good complement to D-efficiency.
G-efficiency Worst-case prediction variance > 50% Ensures no point in the design space has wildly imprecise predictions. Important for RSM.

Don't overthink it

For most experiments, the built-in designs are already highly efficient. Use doe info to check, and only worry about efficiency if you're using D-Optimal or heavily constrained designs.

5 Running Experiments

Automated Execution

After doe generate, you have a runner script that executes all runs sequentially. The tool supports both Bash and Python formats.

Terminal
# Generate a Bash runner (default) $ doe generate --config config.json --format sh --seed 42 # Execute it $ bash run_experiments.sh

The generated script creates the results directory, runs each combination in randomized order, and saves results as run_N.json files.

Terminal
# Generate a Python runner $ doe generate --config config.json --format py --seed 42 # Execute it $ python run_experiments.py

The Python script uses subprocess to call your test script. Useful when you need cross-platform compatibility or want to extend the runner logic.

Writing Effective Test Scripts

Your test script is the bridge between the DOE tool and your real experiment. It must follow a simple contract:

  1. Accept factor values via the configured arg_style (double-dash, env, or positional)
  2. Accept --out <path> specifying where to write the result file
  3. Write a JSON file with keys matching your response names
benchmark.sh — a complete test script example
#!/bin/bash # Parse arguments while [[ $# -gt 0 ]]; do case $1 in --worker_connections) WORKERS=$2; shift 2;; --keepalive_timeout) KEEPALIVE=$2; shift 2;; --gzip_level) GZIP=$2; shift 2;; --out) OUT=$2; shift 2;; *) shift;; esac done # Apply configuration (e.g., update nginx.conf) sed -i "s/worker_connections .*/worker_connections $WORKERS;/" /etc/nginx/nginx.conf sed -i "s/keepalive_timeout .*/keepalive_timeout $KEEPALIVE;/" /etc/nginx/nginx.conf sed -i "s/gzip_comp_level .*/gzip_comp_level $GZIP;/" /etc/nginx/nginx.conf nginx -s reload sleep 5 # Run the benchmark RESULT=$(wrk -t4 -c100 -d30s http://localhost:8080/) THROUGHPUT=$(echo "$RESULT" | grep "Requests/sec" | awk '{print $2}') LATENCY=$(echo "$RESULT" | grep "99%" | awk '{print $2}' | sed 's/ms//') # Write results as JSON echo "{\"throughput\": $THROUGHPUT, \"p99_latency\": $LATENCY}" > "$OUT"

Manual Execution with doe record

For physical experiments (lab work, field tests, manufacturing trials), you don't need a test script. Use doe record to manually enter results:

Terminal
# Record a single run $ doe record --config config.json --run 3 # Record all pending runs interactively $ doe record --config config.json --run all

Tracking Progress

Terminal
$ doe status --config config.json Experiment: Web Server Tuning Design: full_factorial | 8 runs | 3 factors | 2 responses Progress: 5/8 complete [############........] 63% Next run to complete: Run 6 worker_connections = 2048 keepalive_timeout = 15 s gzip_level = 6 Record results with: doe record --config config.json --run 6

Handling Failures and Recovery

A run failed or produced bad data?

Simply delete the offending run_N.json file from the results directory and re-run that specific experiment. The runner script or doe record will regenerate it. Use doe status to see which runs are missing.

If you cannot complete all runs, use the --partial flag on doe analyze and doe optimize to work with whatever data you have.

Exporting Worksheets

For lab and field work, print a worksheet showing all runs with blank columns for recording results by hand:

Terminal
# CSV for Excel or Google Sheets $ doe export-worksheet --config config.json --format csv --output worksheet.csv # Markdown for documentation $ doe export-worksheet --config config.json --format markdown

6 Analyzing Results

Analysis is where DOE pays off. A single command produces a complete statistical analysis of your experiment.

Terminal
$ doe analyze --config config.json

What doe analyze Produces

Reading ANOVA Tables

The ANOVA table is the core output. Here's how to read each column:

ColumnFull NameWhat It Tells You
SourceSource of VariationThe factor or interaction being tested
SSSum of SquaresTotal variation explained by this source. Larger = more influence.
DFDegrees of FreedomNumber of independent comparisons (levels - 1 for main effects)
MSMean SquareSS / DF. The average variation per degree of freedom.
FF-statisticMS(factor) / MS(error). Large F = the factor has a real effect.
p-valueProbabilityProbability that the observed effect is due to chance. p < 0.05 = statistically significant.

Unreplicated designs

When you have no replicates (block_count = 1) and a saturated design, there is no independent error term. The tool uses Lenth's method (pseudo-standard error) to estimate significance, the same approach used by R's FrF2 package.

Understanding Main Effects and Interactions

Main effect: The average change in response when a factor moves from its low level to its high level. For example, a main effect of +15 for temperature means increasing temperature raises the response by 15 units on average.

Interaction effect: When the effect of one factor depends on the level of another. If temperature has an effect of +20 when pressure is high but only +5 when pressure is low, there is a temperature-pressure interaction.

Reading Pareto Charts

The Pareto chart ranks all effects (main effects and interactions) from largest to smallest. A cumulative contribution line shows how much of the total variation is explained. Typically, 2–3 factors account for 80% or more of the variation (the Pareto principle).

What to look for

Focus on the factors above the significance line (dashed red line). These are the "vital few" that truly drive your response. Everything below the line is noise.

Model Diagnostics

The diagnostic panel contains four plots that help you validate the analysis:

PlotWhat to Look ForProblem Sign
Residuals vs. Fitted Random scatter around zero Funnel shape (non-constant variance) or curved pattern (model misfit)
Normal Probability (Q-Q) Points following the diagonal line Systematic departures indicate non-normal errors
Residuals vs. Run Order No trends over time Drift or trending suggests an uncontrolled variable changing during the experiment
Predicted vs. Actual Points close to the 45-degree line Systematic deviation means the model is missing important terms

Partial Analysis and Filtering

Terminal
# Analyze with incomplete data (some runs not yet finished) $ doe analyze --config config.json --partial # Skip generating plots (faster, for CI/CD or headless servers) $ doe analyze --config config.json --no-plots # Export results to CSV for further analysis in R, Excel, etc. $ doe analyze --config config.json --csv exports/

7 Optimization

Once you understand which factors matter, optimization finds the best settings.

Single-Response Optimization

Terminal
# Optimize for a specific response $ doe optimize --config config.json --response throughput

The optimizer does three things:

  1. Reports the best observed run — the actual run with the best measured result
  2. Fits a response surface model — linear and quadratic models using least squares
  3. Finds the true optimum — uses L-BFGS-B optimization with multi-start to find the global optimum on the fitted surface, which may lie between tested levels

Response Surface Modeling

Response Surface Methodology (RSM) fits a mathematical model to your data, then uses that model to predict the response at any point in the factor space — even points you didn't test. This is what allows the optimizer to find settings between your tested levels.

Linear vs. Quadratic models

The tool automatically fits both. A linear model captures main effects and interactions. A quadratic model also captures curvature (the sweet spot). If the quadratic model fits significantly better (higher R-squared), the optimum likely lies in the interior of the factor space rather than at a corner.

Multi-Objective Optimization

When you have conflicting goals (e.g., maximize throughput AND minimize latency), use --multi to find the best compromise:

Terminal
$ doe optimize --config config.json --multi ============================================================ MULTI-OBJECTIVE OPTIMIZATION Method: Derringer-Suich Desirability Function ============================================================ Overall desirability: D = 0.7432 Response Weight Desirability Predicted Direction ----------------------------------------------------------------- throughput 2.0 0.8125 3842 req/s ↑ p99_latency 1.0 0.6215 38.5 ms ↓ Recommended settings: worker_connections = 1820 keepalive_timeout = 62 s gzip_level = 3 Trade-off summary: throughput: 3842 (best observed: 4210, sacrifice: +368) p99_latency: 38.5 (best observed: 28.1, sacrifice: +10.4)

The desirability function converts each response into a 0–1 scale (0 = worst, 1 = best), then combines them using a weighted geometric mean. The weights in your config control the relative importance of each response.

Steepest Ascent/Descent

For sequential experimentation (Phase 1 RSM), use --steepest to generate a table of follow-up experiments along the gradient direction:

Terminal
$ doe optimize --config config.json --response throughput --steepest Steepest Ascent Path (for throughput, maximize): Step worker_connections keepalive_timeout gzip_level Predicted 0 1280.0 45.0 3.5 3120 1 1536.0 51.0 3.0 3340 2 1792.0 57.0 2.5 3560 3 2048.0 63.0 2.0 3780 4 2304.0 69.0 1.5 4000 Run these experiments and check if the response keeps improving. Stop when the response starts declining — you've found the region of the optimum.

When to use steepest ascent

Use it when your initial screening design suggests the optimum is outside the tested region. Follow the path of improvement until the response starts declining, then run a new RSM design (CCD or Box-Behnken) centered at the new best point.

8 Advanced Features

Design Augmentation

Augmentation lets you add runs to an existing design without re-running what you've already completed. This is essential for sequential experimentation.

Fold-Over: De-aliasing Confounded Effects

If your fractional factorial design has aliased (confounded) effects and you need to separate them, a fold-over mirrors all factor levels (swaps high and low). This doubles your run count but breaks the aliasing.

Terminal
$ doe augment --config config.json --type fold_over

When to use: After a fractional factorial shows significant effects, but you can't tell which aliased term is really driving the response.

Star Points: Enabling RSM After Factorial

Adding axial (star) points to a 2-level factorial design converts it into a Central Composite Design, enabling quadratic response surface modeling.

Terminal
$ doe augment --config config.json --type star_points

When to use: When your factorial analysis reveals significant curvature and you need to model the response surface to find the true optimum.

Center Points: Detecting Curvature

Adds 3 replicate runs at the center of the design space (midpoint of all continuous factors). These runs serve two purposes: detecting curvature and estimating pure error.

Terminal
$ doe augment --config config.json --type center_points

When to use: After a 2-level design when you suspect the relationship isn't purely linear. If center points show significantly different results from the factorial average, curvature is present.

Power Analysis

Before running an expensive experiment, check whether your design has enough runs to detect the effects you care about:

Terminal
$ doe power --config config.json --sigma 5.0 --delta 10.0 Power Analysis Design: full_factorial (8 runs) Error std dev (sigma): 5.0 Min detectable effect (delta): 10.0 Significance level (alpha): 0.05 Power: 0.93 Interpretation: You have a 93% chance of detecting an effect of size 10.0 or larger. This is above the recommended threshold of 0.80. Your design has sufficient power.

Power below 0.80?

If power is low, you have several options: (1) increase block_count to add replicates, (2) switch to a design with more runs, (3) accept that you can only detect larger effects. Don't run an underpowered experiment — you'll spend time and resources without being able to draw conclusions.

Adaptive/Sequential Experimentation

Use doe next-batch for iterative experimentation where each batch of runs informs the next:

Terminal
$ doe next-batch --config config.json --strategy bayesian

This command analyzes your current results and suggests the most informative next set of experiments to run. Six strategies are available via --strategy (or the adaptive config block): refine focuses near the best region, explore maximizes space coverage, balanced mixes both, model_guided targets where the fitted surface is most uncertain, bayesian uses Gaussian-process expected improvement, and multi_objective optimizes desirability across several responses. Use --state-name to branch alternative follow-up trajectories from the same starting data.

The Wider Toolkit

Beyond the core workflow, the CLI includes tools for bootstrapping, simulation, and cross-experiment analysis — see the Technical Reference for every flag:

HTML Report Generation

Terminal
$ doe report --config config.json --output experiment_report.html

The report is fully self-contained HTML with all plots embedded as base64 images. No external dependencies. Share via email, Slack, wiki, or any file-sharing tool.

Contents include: design summary, ANOVA tables, effects tables, Pareto charts, main effects plots, normal/half-normal probability plots, diagnostic panels, 3D response surfaces, optimization recommendations, and the full design matrix.

Integration with AI Assistants

Use the DOE Helper with AI tools like ChatGPT or Claude for:

See the AI Prompts page for ready-to-use prompts.

9 Best Practices

How Many Factors Are Too Many?

FactorsApproachRationale
2–5Full factorial or CCDAffordable run count. Full interaction analysis.
6–12Screen first (PB or DSD), then optimize top 3–5Too many runs for full factorial. Screen to find the vital few.
13+Plackett-Burman screening, then sequential refinementScreening is mandatory. Only test the survivors in detail.

Replication and Blocking

Why replicate?

Replication (via block_count) gives you an independent estimate of experimental error, makes significance tests more powerful, and helps you detect if conditions changed between batches. For critical experiments, always use at least 2 blocks.

Common Mistakes and How to Avoid Them

Changing one factor at a time (OVAT)

The mistake: Testing factors one at a time while holding others constant.

Why it's bad: OVAT requires more runs than DOE and completely misses interaction effects. Two factors might be fine individually but terrible (or great) together.

The fix: Use any DOE design. Even a simple full factorial with 3 factors and 2 levels (8 runs) gives you complete information about all main effects AND all interactions.

Not randomizing run order

The mistake: Running experiments in a systematic order (all low values first, then all high values).

Why it's bad: If conditions drift over time (temperature, load, degradation), your results will be confounded with the time trend.

The fix: The DOE Helper randomizes run order automatically. Use --seed for reproducible randomization.

Testing too many levels

The mistake: Using 5 levels for every factor "to be thorough."

Why it's bad: A 5-factor experiment with 5 levels each = 3125 runs. With 2 levels it's just 32 runs (or 16 with fractional factorial).

The fix: Start with 2 levels per factor. If curvature exists, add center points or switch to CCD. You rarely need more than 3 levels for continuous factors.

Ignoring practical significance

The mistake: Declaring a factor important because p < 0.05, even though its actual effect is tiny.

Why it's bad: Statistical significance is not the same as practical significance. A factor that changes throughput by 0.1% may be "significant" with enough data but not worth optimizing.

The fix: Always look at the effect size (the actual magnitude of change), not just the p-value. Use the Pareto chart to see the relative contribution of each factor.

When to Use DOE vs. Other Methods

SituationMethodWhy
Multiple factors, want interactionsDOEDesigned for this exact problem
Single continuous parameter to tuneGrid search or bisectionDOE is overkill for 1 parameter
Huge search space, cheap evaluationsBayesian optimizationBetter for 20+ dimensional spaces with fast evaluations
Need to understand causal relationshipsDOEOnly controlled experimentation proves causation
Observational data onlyRegression / MLCan't run experiments, must work with what you have

Tips for Getting the Most Out of Your Experiments

  1. Always preview first. Use doe generate --dry-run and doe info before committing.
  2. Check power before running. Use doe power to verify your design can detect the effects you care about.
  3. Start with screening. If you have more than 5 factors, screen first with PB or DSD before investing in RSM.
  4. Use center points. They're cheap (3 extra runs) and tell you if curvature exists.
  5. Examine diagnostics. Always check the residual plots. A bad model gives bad recommendations.
  6. Document everything. Use doe report to generate a permanent record of your experiment.
  7. Iterate. Your first experiment rarely gives the final answer. Use what you learn to design a better follow-up.

10 Troubleshooting

Common Error Messages

ErrorCauseSolution
No result files found The results directory is empty or doesn't exist Check that out_directory in config matches where results are saved. Run doe status to verify.
Factor X requires exactly 2 levels Fractional factorial, PB, or CCD requires 2-level factors Ensure all factors have exactly 2 levels, or switch to a design that supports more.
Box-Behnken requires 3+ factors You have fewer than 3 factors Use CCD or full factorial for 2-factor experiments instead.
Response 'X' not found in run_N.json The result file is missing a key that matches your response name Verify that your test script writes JSON with keys exactly matching the name fields in your responses config.
Duplicate factor names Two factors have the same name Every factor name must be unique. Check for typos.
Invalid JSON in config file Syntax error in config.json Check for trailing commas, missing quotes, or mismatched brackets. Use a JSON validator.

Missing Results

If some runs failed or weren't completed:

Terminal
# See which runs are missing $ doe status --config config.json # Analyze with available data only $ doe analyze --config config.json --partial # Re-record a specific failed run $ doe record --config config.json --run 5

Design Validation Failures

The tool validates your config against the selected design type. Common validation issues:

Result Format Issues

Check your JSON output

The most common issue is response names in the result file not matching the config. Names are case-sensitive. If your config says "throughput", your result file must use "throughput" — not "Throughput" or "THROUGHPUT".

Verify a result file is valid:

Terminal
# Check that the file is valid JSON with the expected keys $ python -m json.tool results/run_1.json { "throughput": 3420, "p99_latency": 47.2 }

For additional help, see the Quick Start for command reference, Theory for statistical background, or AI Prompts to get AI-assisted explanations of your results.