CLI Mode, Headless Execution, Result Files, and Reproducible Runs: Diagnostics, Failure Modes, and Production Practices
Headless operation fails in several distinct layers: the wrapper may point at the wrong file, JMeter may fail to load/initialize, samples may fail while the engine completes, the gate may reject otherwise valid samples, or report generation may collide with an old directory. Preserve the earliest evidence and identify the layer before changing load, heap, retries or the target.
Learning objectives
- Recognize GUI load execution as a generator-validity problem.
- Prevent evidence overwrite and unsafe force-delete use.
- Keep secrets out of commands/manifests/logs.
-
Use
jmeter.logto diagnose engine/config problems. - Separate process/engine success from sample/SLO pass.
- Detect and control JMeter/Java version drift.
1. Preserve first-failure evidence
127.0.0.1:8021, ≤2×4.
Preserve exact command, cwd, versions, JMX/property hashes,
wrapper/pre-manifest, JTL if any, jmeter.log, engine
exit, gate output, report state, generator state and target events
before repair. Do not delete/overwrite the failed run directory.
2. Diagnostic sequence
CLI execution turns a JMeter plan into a reproducible process contract: explicit inputs enter one engine process, the process emits separate raw/log/report artifacts, and a post-run validator decides whether the observed workload is acceptable.
flowchart TD E[Preserve command + JTL + jmeter.log + manifest + target evidence] --> V[Confirm JMeter / Java / plugin / tool versions] V --> C[Confirm exact JMX / data / properties / CLI + authorized target] C --> S[Validate tree scope + resolved variables/properties + expected sample count] S --> P[Inspect protocol/session/data state] P --> G[Inspect generator JVM / CPU / GC / disk / network] G --> T[Inspect SUT telemetry / received work] T --> X[Inspect CI/container/remote workspace/result-transfer state if relevant] X --> F[Least destructive correction] F --> R[Small controlled rerun]
3. Failure mode: running meaningful load in GUI
Symptoms: higher generator CPU/memory, UI freezes, retained listener data and harder-to-reproduce results. Repair: use GUI only to author/validate tiny cases; save the JMX and run the bounded load through the recorded CLI contract. Do not conclude the server is slow from a saturated GUI injector.
4. Failure mode: overwriting prior evidence
Broken:
jmeter -n -t plan.jmx -l results/results.jtl -j results/jmeter.log
# repeated tomorrow with the same paths
Depending on file/report behavior and surrounding scripts, the second invocation can mix/replace evidence or fail ambiguously. Repair: allocate a new run ID directory and refuse reuse.
5. Failure mode: unsafe -f
Broken automation constructs output paths from an unchecked variable
and adds -f “so stale files never block the job.”
Current JMeter defines -f to force-delete existing
result files and web report folders.
Repair: remove -f from the general launcher. Use
immutable run directories. If a specialized disposable workspace
ever uses -f, verify the resolved path is a dedicated
generated child of a known workspace before invoking JMeter.
6. Failure mode: embedding credentials in CLI
Commands can be visible in process listings, shell history, CI logs and manifests. Current JMeter docs explicitly warn that proxy credentials on the command line may be visible to other system users.
Repair: keep non-secret workload knobs in -J; inject
real secrets using an approved secret mechanism that is not
echoed/manifested, and redact diagnostic output. The mandatory
fixture uses no authentication.
7. Failure mode: ignoring jmeter.log
A JTL may be empty or shorter than expected because JMX parsing,
script/class/plugin initialization, report generation or engine
shutdown had a problem. If the wrapper only parses JTL and discards
jmeter.log, the root cause is lost.
Always retain -j run/jmeter.log and search
ERROR/FATAL/WARN context before changing the SUT.
8. Failure mode: process exit success interpreted as SLO success
A JMeter invocation can complete at the process layer while JTL contains HTTP/assertion failures or an unacceptable p95. That is why the Chapter 21 gate parses result rows independently.
Never rewrite the engine exit code to “failed because p95” without also preserving the original engine status. Store both.
9. Failure mode: floating JMeter/Java versions
Two scheduled runners pick different JMeter or Java versions from
PATH. Behavior/performance changes can then be
attributed incorrectly to the SUT.
Repair: standardize/pin an approved runtime, capture
jmeter -v and java -version every run, and
reject/flag unexpected versions before a regression comparison.
10. Intentionally broken example: missing JMX file
Create a dedicated failure directory, then intentionally invoke a nonexistent plan directly so the JMeter process—not the safe wrapper's preflight—owns the failure:
$FailDir = "F:\Labs\p21-cli-lab\results\p21-missing-jmx"
New-Item -ItemType Directory -Force $FailDir | Out-Null
& "$env:JMETER_HOME\bin\jmeter.bat" `
-n `
-t "F:\Labs\p21-cli-lab\plans\missing-plan.jmx" `
-q "F:\Labs\p21-cli-lab\config\local.properties" `
-l "$FailDir\results.jtl" `
-j "$FailDir\jmeter.log"
$EngineExit = $LASTEXITCODE
$EngineExit | Set-Content "$FailDir\engine-exit.txt"
Expected: non-success process/engine evidence,
jmeter.log indicating plan/file load failure, no valid
8-sample JTL workload, and no matching target work events. Preserve
all files. The target is healthy; this failure occurred before
workload execution.
Repair: do not copy a random replacement plan or
switch target. Use the existing hashed
plans/cli-local.jmx through the safe launcher with a
new run ID.
11. Failure mode: report output directory already contains files
-o requires a new/empty destination. A fixed
report-output path from yesterday can make report
generation fail even when JTL is valid.
Repair: generate inside a unique run directory or use a new
directory for later -g. Preserve the raw JTL; report
generation can be retried without rerunning target load.
12. Failure mode: global DEBUG under load
-LDEBUG can dramatically enlarge
jmeter.log and consume generator CPU/disk. Use a narrow
category only in a small reproduction. Record any logging override
because the generator workload changed.
13. Causal symptom table
| Symptom | Generator/execution cause | Target cause to distinguish | Evidence |
|---|---|---|---|
| No target work events | missing/invalid JMX, preflight/engine failure | target down | engine exit + jmeter.log + target health/event delta. |
| 8 samples but some failed | HTTP/assertion/data issue | server correctness/error | JTL failureMessage/code + target events. |
| p95 rises, target service time flat | generator CPU/GC/log/save/report/network | server slowdown | generator state + JTL + target service_wall_ms. |
| HTML missing but JTL valid | report path/generation problem | SUT regression | jmeter.log/report dir + complete JTL/target events. |
| CI differs from local | version/path/workspace/container/runtime drift | target regression | manifest versions/hashes/cwd + target evidence. |
14. Troubleshooting shortcuts to reject
- Do not add blanket retries or arbitrary long sleeps.
- Do not raise heap before identifying avoidable listeners/log/result cost.
- Do not mass-disable listeners without evidence and then lose required diagnostics.
- Do not use global property hacks to force missing runtime state.
- Do not disable TLS/RMI verification.
- Do not test a production endpoint because localhost/CI paths failed.
- Do not increase threads/sample count while process/artifact validity is unresolved.
- Do not delete failed JTL/log/manifests to free space before diagnosis.
Knowledge check
What proves the missing-JMX failure is not target saturation?
JMeter fails to load/start the intended plan, target health remains available, and no matching work events occur.
Why is -f omitted from the general launcher?
Unique immutable run directories preserve evidence and avoid destructive cleanup from a bad path.
Why should a command manifest exclude secrets?
Commands/manifests can be retained or exposed through logs/process history; they are evidence, not secret stores.
What if engine exit=0 but JTL failures=2?
Engine execution succeeded; the post-run correctness gate fails. Preserve both statuses.
What must be controlled before comparing two scheduled runs?
JMX/property hashes, JMeter/Java/plugin versions, resolved workload, generator state and target environment/evidence.
Official references and version notes
-
JMeter Getting Started — CLI mode
—
-n,-t,-l,-j,-g,-e,-o,-J,-L, remote flags, and CLI/load guidance. -
JMeter Listeners / Result files
— CSV versus XML, save-service defaults, CLI
-llistener, result fields, and memory guidance. -
JMeter Generating Dashboard Report
— dashboard-required CSV fields,
-g,-e -o, output-folder rules, graphs, and report properties. - JMeter Best Practices — GUI authoring/debugging and CLI execution for load.
- Apache JMeter downloads — current stable release and Java requirement.
Version-sensitive statements were rechecked against current Apache
JMeter primary documentation on 2026-09-05. The course baseline
remains Apache JMeter 5.6.3 with a Java 17 JDK;
JMeter 5.6.3 requires Java 8+. JMeter's own manual says GUI mode
is for building/debugging while CLI mode must be used for load
testing. Current CLI flags include -n (CLI),
-t (JMX), -l (JTL), -j (run
log), -g <CSV> (report only),
-e (report after test), and -o (report
output). The report output folder must not exist or must be empty.
-f force-deletes an existing result file/report
folder before a test, so the safe launcher in this chapter
intentionally does not use it; instead it refuses to reuse an
existing run directory. CSV result files are smaller than XML and
are the normal large-run choice. Current CSV defaults include
timing/status/thread and byte fields such as
timeStamp, elapsed, label,
responseCode, success,
bytes, sentBytes,
grpThreads, and allThreads when their
save-service fields are enabled (the current defaults required by
the dashboard are documented as correct unless changed). Response
data is not supported in CSV. JMeter process/engine completion is
therefore treated separately from a post-run SLO/result gate: a
launcher first records the engine exit code, then validates JTL
sample counts/failures/latency. A zero engine exit is not used as
evidence that every sample met an SLO.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.