skip to content

In JMeter, does a Post-Processor still run against a response that a Response Assertion is about to fail?

level: seniorimportance: should knowfreq 45%

answer

  1. Two families both read the finished result
  2. Only one of them can be first
  3. Steps four and five, in that order
  4. Nothing gates extraction except a missing or ignored result

basics

~10 s

Yes. Post-Processors are step 4 and Assertions are step 5, so extraction happens against the error body before anything has judged it. Only a null or ignored SampleResult stops a Post-Processor.

solid answer

~40 s

Post-Processors run first. `JMeterThread` calls `runPostProcessors(...)` and then `checkAssertions(...)` with no branch between them, and the only guards on either are the shared `if (result != null)` and `if (!result.isIgnore())` checks — no assertion outcome gates extraction. An HTTP 500 still produces a result object, so an extractor under that sampler parses the error page, finds nothing, and leaves the variable at its configured default — often blank. The assertion then marks the sample failed, and the thread walks on to the dependent request carrying that empty value. The ordering runs the other way too: because a Post-Processor executes first, a script that calls `prev.setSuccessful(false)` has already changed what the assertion sees. Guard extraction on the sampler's status if you need it not to run on failures.

code

groovy · 7 lines
groovy
// JSR223 PostProcessor - runs at step 4, before any Assertion has judged this sample
if (prev.getResponseCode() != '200') {
    log.warn("skipping extraction, HTTP ${prev.getResponseCode()}")
    return
}
def body = new groovy.json.JsonSlurper().parseText(prev.getResponseDataAsString())
vars.put('orderId', body.id as String)

go deeper

for a junior

Recall the position of the two families: Post-Processors run before Assertions, so extraction is never gated on a check passing.

for a middle

Explain that both share the same two guards and nothing else, and that a 5xx still produces a result object an extractor will happily parse.

for a senior

Recognise the failure shape in a real run, where one honest red row is followed by green rows that measured the wrong thing, and defend the extraction rather than hope the assertion protects it.

for a principal

Own the plan-wide policy for what a failed dependency should do to the rest of an iteration, and make sure a broken correlation cannot pass as a green result.

## The order Post-Processors run at step 4 and Assertions at step 5. In `JMeterThread.executeSamplePackage(...)` the two calls are adjacent and unconditional relative to each other: ```java threadContext.setPreviousResult(result); runPostProcessors(pack.getPostProcessors()); // step 4 checkAssertions(pack.getAssertions(), result, ctx); // step 5 notifyListeners(sampleListeners, result); // step 6 ``` There is no branch between them. The only things that can stop the Post-Processors are a `null` `SampleResult` and the `isIgnore` flag, and a sampler that failed an HTTP call still produces a very real result object — it just carries a 5xx code and a failure flag. So yes: the extractor runs, and it runs against the error body. ## Why this matters more than it sounds Extraction against a response nobody has checked yet is how a run keeps going with wrong data. The sequence in practice: 1. `POST /orders` returns HTTP 500 with an error page in the body. 2. The `JSON Extractor` under it runs, finds no `$.orderId`, and leaves the variable at whatever the configured default says — frequently blank, because a blank default is the path of least resistance when authoring. 3. The `Response Assertion` runs and marks the sample failed. 4. The listener records the failure. 5. The thread moves on to `GET /orders/${orderId}` — which now goes out with an empty path segment, hits a different endpoint entirely, and very possibly returns 200. The result is one honest red row followed by a run of green rows that measured nothing. The assertion did its job; it simply did it after the damage. ## What you can and cannot do about it You cannot reorder the two families — the order is fixed in the engine and there is no property or flag that swaps them. What you can do is make the extraction defend itself, or make the failure stop the thread: - **Guard the extraction in script.** A JSR223 PostProcessor sees the sampler's own result through its `prev` binding, because `setPreviousResult(result)` was called immediately before it. Check the status first and return early. - **Leave the default unset rather than blank.** If nothing writes the variable, the next request carries the literal `${orderId}`, which is unmistakable in a listener; a blank silently produces a valid-looking but meaningless URL. - **Make the sampler's failure terminate the thread** rather than letting it walk into the dependent request. What the available error actions are, and which to pick, belongs to the sampler-error material rather than to sequencing. - **Read the run, not the summary.** A run where the failure count is small but the failures cluster at the start of an iteration is the shape this defect makes. ## The symmetric fact The ordering also runs the other way and is worth stating: because Post-Processors run first, a Post-Processor can change what the assertion sees. A script that calls `prev.setSuccessful(false)`, or that rewrites the response data on the result object, has already done so by the time `checkAssertions(...)` is invoked. And because `checkAssertions(...)` ends by calling `setLastSampleOk(...)`, the `JMeterThread.last_sample_ok` variable that controllers read reflects the post-assertion verdict, not the raw sampler outcome. ## Summary | Question | Answer | |---|---| | Does a Post-Processor run on a failed sample? | Yes — step 4 precedes step 5 | | Does a failing Assertion undo the extraction? | No — the write already happened | | What stops a Post-Processor? | A `null` `SampleResult`, or one a scripted sampler flagged with `setIgnore()` | | Can a Post-Processor influence an Assertion? | Yes — it mutates the result first |

  • Can a Post-Processor change the verdict an Assertion afterwards reaches?
    Yes, because it runs first. A script that mutates the SampleResult, for example by calling setSuccessful(false) or rewriting the response data, has done so before checkAssertions is invoked, so the assertion evaluates the mutated object rather than the raw sampler outcome.
  • Why is a blank default on an extractor more dangerous here than no default at all?
    A blank silently produces a valid-looking request, such as a URL with an empty path segment, which may even return 200 and be recorded green. With no default written, the next request carries the literal reference instead, which is unmistakable in a listener and in the results file.

saying these in an interview costs you the question

  • Says a failing assertion cancels the post-processors for that sampler
  • Thinks assertions run first because checking sounds like it comes before extraction
  • Assumes an extractor is skipped on a non-2xx response
  • Says a post-processor cannot influence what an assertion sees
  • Believes a failed sample stops the thread by default