In a JMeter JSR223 PreProcessor, which sample result does the bound prev object hold?
answer
- Set after a sample, not before
- One binding is behind, another is ahead
- Ask what has run when a pre-processor fires
- Nothing has sampled yet on the first one
basics
~20 sThe result of the previous sampler, not the one about to run. JMeter only calls setPreviousResult after a sample completes, so in a PreProcessor prev is one sampler behind, and it is null before the thread's first sample.
solid answer
~30 s`prev` is bound from `ctx.getPreviousResult()`, and `JMeterThread` writes that field only *after* a sample returns. Inside a PreProcessor the sampler has not run yet, so `prev` still holds the result of whatever sampled last — and on the thread's very first sampler it is `null`, because nothing has set it. The binding that refers to the sampler about to run is `sampler`: `JMeterThread` calls `setCurrentSampler(current)` before it invokes the pre-processors. Inside a PostProcessor the picture flips: `setPreviousResult(result)` has just run, so `prev` is the result of the sampler this element is attached to.
go deeper
Recall that prev is a SampleResult and sampler is the current Sampler. In a PostProcessor prev is the reply you just got, which is the case you will meet first.
Explain the engine sequence: current sampler set, pre-processors, timers, sample, previous result set, post-processors. That order is what makes prev lag by one inside a PreProcessor.
Diagnose the once-per-thread failure at the start of a run as a null prev on the first sampler, and write the guard rather than depending on ordering that a plan edit can change.
Decide where correlation logic lives across a team's plans - reading prev in a PostProcessor next to its own sampler, versus a PreProcessor that reaches backwards - so plan fragments stay reorderable.
Two of the bindings JMeter hands a JSR223 script point at samples, and they point at different things depending on where in the sequence the element sits. ## What `JMeterThread` does around one sampler `JMeterThread.executeSamplePackage` runs a fixed sequence for each sampler: 1. `threadContext.setCurrentSampler(current)` 2. `runPreProcessors(...)` 3. `delay(pack.getTimers())` 4. `doSampling(...)` — the request actually goes out 5. `threadContext.setPreviousResult(result)` 6. `runPostProcessors(...)`, then assertions, then listeners `prev` is bound from `ctx.getPreviousResult()` and `sampler` from `ctx.getCurrentSampler()`, both read at step 2 or step 6 depending on the element. ## The two positions | Element | `sampler` refers to | `prev` refers to | |---|---|---| | JSR223 PreProcessor | the sampler about to run | the result of the sampler *before* it | | JSR223 PostProcessor | the sampler that just ran | the result that sampler just produced | Note what step 1 also does: `setCurrentSampler` first copies the old current sampler into `previousSampler`, so `ctx.getPreviousSampler()` in a PreProcessor names the step before this one. ## The null case Nothing sets `previousResult` when a thread starts — `initRun` sets the variables, thread number, thread group and engine, but not a result. So on the thread's **first** sampler of the run, a PreProcessor sees `prev == null`, and a script that dereferences it fails on that one invocation. The symptom is characteristic: the failure appears once per thread, at the start of the run, and never again, because from the second sampler onwards `previousResult` is populated and stays populated — it is not cleared between iterations of the thread loop. Guard it explicitly rather than relying on it being set: ```groovy if (prev != null && prev.isSuccessful()) { vars.put("lastCode", prev.getResponseCode()) } ``` When a JSR223 element's script raises, the element catches it and writes `Problem in JSR223 element named: '<name>'` to `jmeter.log` at error level; it does not fail the sampler for you. ## What `prev` gives you `SampleResult` carries the whole record of the previous sample — `getResponseCode()`, `getResponseMessage()`, `getResponseDataAsString()`, `getSampleLabel()`, `getTime()`, `isSuccessful()`, and the subresults. That makes a PreProcessor the natural place to build the *next* request out of the previous reply: read the id off `prev`, write it with `vars.put`, and let the sampler that is about to run interpolate it. One caching detail: after each sample JMeter calls `cleanAfterSample()`, which nulls the result's cached `responseDataAsString` (and clears `ctx.getSamplerContext()`). The bytes are still there, so calling `getResponseDataAsString()` on a carried-over `prev` simply re-decodes them rather than returning a stale cached string. ## Not to be confused with - `SampleResult` with a capital S — the JSR223 **Sampler** binds that name to the result it is building, and the JSR223 **Assertion** binds it to the response under test alongside `AssertionResult`. - `sampleResult` and `sampleEvent` — bound only by the JSR223 **Listener**, from the event it was handed.
- In a JMeter JSR223 PreProcessor, which binding refers to the sampler that is about to run?`sampler`. `JMeterThread` calls `setCurrentSampler(current)` before it runs the pre-processors, so `ctx.getCurrentSampler()` — and therefore the `sampler` binding — is the element that is about to be sampled. Cast it to its concrete type to alter it, for example `sampler.addArgument("token", t)` on an HTTP Request.
- Does JMeter clear prev between iterations of a thread loop?No. `previousResult` is only reassigned when the next sample completes, so at the top of iteration two it still holds the last result of iteration one. Only `cleanAfterSample` runs in between, and that clears the cached response string and the sampler context, not the result reference.
saying these in an interview costs you the question
- Says prev is the result of the sampler about to run
- Assumes prev is never null in a PreProcessor
- Confuses prev with the capital-S SampleResult binding
- Thinks JMeter resets prev at each thread-loop iteration
- Cannot say which binding names the upcoming sampler