A JMeter non-GUI run where every sample failed still exited 0. What does JMeter's exit code report?
answer
- The shell sees a number, not a verdict
- Ask what the JVM was reporting on
- Start-up and shutdown are the exceptions
- Look for a threshold flag; there is none
basics
~20 sJMeter's exit code reports whether the process itself completed, not whether the test passed. A non-GUI run returns 0 at a 100 percent error rate; only a start-up throwable or a shutdown that leaves threads running returns 1.
solid answer
~40 s`jmeter -n` exits `0` whenever the engine started, ran and shut down. Failed samplers, failed assertions and a 100% error rate change nothing about it. In JMeter 6.0.0 the non-GUI path has exactly two `System.exit(1)` calls: one in `JMeter.start()`, from the `catch (Throwable)` wrapping the whole CLI run (a missing `-t` file, a plan that will not load), and one in `StandardJMeterEngine` when a test that was explicitly told to stop still has live threads — the call that `jmeterengine.stopfail.system.exit` gates. Neither inspects a result. JMeter also ships no threshold language: no element, property or flag says *fail above 1% errors*. The verdict has to be manufactured after the run, by a step that reads the JTL and exits non-zero itself.
code
bash · 9 lines$ jmeter -n -t checkout.jmx -l results.jtl
Creating summariser <summary>
Created the tree successfully using checkout.jmx
Starting standalone test @ ...
summary = 1200 in 00:01:00 = 20.0/s Avg: 108 Min: 41 Max: 980 Err: 1200 (100.00%)
Tidying up ... @ ...
... end of run
$ echo $?
0go deeper
Recall the shape: jmeter -n returns 0 for a run that completed, whatever the samples did. A green load step only tells you JMeter finished, never that the service answered.
Name the two non-zero paths — a throwable during start-up and a stop request whose threads never died — and be able to say that neither of them inspects a sample result.
Show that you check the results file and its row count as well as the status code, so that 'ran perfectly' and 'never ran at all' cannot look identical to the pipeline.
Decide, across a fleet of JMeter plans, which artefact the verdict reads and who maintains that rule, so no team's plan can pass a stage by producing nothing at all.
## What the status code is actually about `jmeter -n -t plan.jmx -l results.jtl` is an ordinary JVM process, and its exit status answers one question: **did the process finish its work without an unhandled error?** It never answers *did the system under test behave?* A run in which all 1,200 samples came back `Connection refused` ends exactly the way a clean run ends — the engine started, the threads ran their loops, the listeners were told the test had ended, JMeter printed `... end of run`, the JVM returned `0`, and the build step after it went green. Three weeks of that is a real and common failure: the nightly job is green, the dashboard is being generated, and nobody has looked at the `Err:` figure. ## The only two non-zero paths in JMeter 6.0.0 Grep the shipped sources and the CLI has exactly two places that hand back a failing status, and neither of them looks at a `SampleResult`: 1. **A throwable escaping start-up.** `JMeter.start(String[])` wraps the whole CLI path in a `catch (Throwable)` that logs `An error occurred: ` and calls `System.exit(1)`. A `-t` path that does not exist, a plan that will not deserialise, an output folder JMeter refuses to write — all real non-zero exits, and all of them about *arguments*, not results. 2. **A shutdown that got stuck.** When a test has been explicitly asked to stop *now* and `StandardJMeterEngine` still finds live threads after its wait, it logs `One or more test threads won't exit; see log file.`, prints `Fatal error, could not stop test, exiting` and calls `System.exit(1)`. The `jmeterengine.stopfail.system.exit` property gates that one call, and it is a report about a wedged JVM. Everything else exits `0`. That includes the case candidates find hardest to believe: a **test-tree compile error**. `StandardJMeterEngine.run()` traverses the plan with `PreCompiler` inside a `try`; on a `RuntimeException` it logs `Error occurred compiling the tree:` and simply returns. No listener is ever told the test started, so the `-l` results file is never even opened — and the process still exits cleanly. A pipeline that reads only the status code cannot tell *ran perfectly* from *never ran at all*. ## There is no threshold to set The second half of the answer matters as much as the first. JMeter has no threshold language. There is no plan element that says "fail above 1% errors", no property in `bin/jmeter.properties` that turns an error rate into an exit status, and no CLI flag that does it. Assertions exist, and they do real work — they turn a wrong-but-200 response into a sample marked failed — but an assertion result lives in the sample, not in the process. It changes a row in the results file and, at most, what the engine does next inside the run. It never reaches the shell. ## Where a real verdict can come from | Signal | Where it lives | Can it fail a build on its own? | |---|---|---| | Process exit code | the shell | No — `0` unless start-up or shutdown broke | | `success` column | the `-l` JTL file | Yes, once a step counts it and exits non-zero itself | | Summariser `Err:` figure | stdout and `jmeter.log` | Only if a step parses that text | | Assertion results | rows inside the JTL | They mark rows; they do not stop the process | So the pipeline shape that actually gates is two steps, not one: run JMeter, then run a check that reads the artefact JMeter left behind and exits non-zero on its own judgement. Everything this leaf is about follows from that: the check has to name a column, it has to survive a run that produced no rows at all, and it has to be as maintained as the plan it guards. ## What to say in the room Answer the literal question first — the status reports the process, not the samples — then name the two exceptions, then say the consequence out loud: *a green JMeter step is not evidence that the system responded.* That last sentence is the one interviewers are listening for.
- Which JMeter command-line flag makes the run exit non-zero once the error rate passes a limit?None. JMeter 6.0.0 has no threshold option on the command line and no threshold element in the plan; the flags select the plan, the results file, properties, remote engines and the report. A failing status has to come from a separate step that reads the JTL after the run.
- A JMeter plan with a malformed function call logs 'Error occurred compiling the tree:'. What does the CLI return?0. StandardJMeterEngine.run() catches the RuntimeException from PreCompiler, logs that line and returns before any listener is told the test started, so the -l file is never opened. The build sees a clean exit and an absent results file.
It is the difference between a courier confirming the van completed its route and confirming the parcels arrived intact. The route log comes back clean either way.
saying these in an interview costs you the question
- Says a failed assertion makes jmeter -n exit non-zero
- Believes JMeter has a built-in error-rate threshold
- Reads a green JMeter step as proof the endpoint answered
- Thinks a missing results file means zero errors
- Expects the HTML dashboard step to fail the build on errors