Fix JMeter JSR223 Groovy script errors: ScriptException, MissingPropertyException, null pointer errors, vars vs props scope, and compilation caching.
JSR223 Groovy Script Errors in JMeter
Section titled โJSR223 Groovy Script Errors in JMeterโSymptom
Section titled โSymptomโWhen executing JSR223 Samplers, PreProcessors, PostProcessors, or Assertions, samples turn red or errors appear in jmeter.log:
2026-08-18 10:15:32,410 ERROR o.a.j.m.JSR223PostProcessor: Problem in JSR223 script, JSR223 PostProcessorjavax.script.ScriptException: groovy.lang.MissingPropertyException: No such property: token for class: Script1 at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:324)Or for null pointers when accessing variables:
java.lang.NullPointerException: Cannot invoke method split() on null object at Script1.run(Script1.groovy:4)The error causes the sampler to fail and logs a stack trace for every virtual user thread execution.
Quick diagnosis (TL;DR)
Section titled โQuick diagnosis (TL;DR)โMissingPropertyException: You referenced an undeclared variable directly (e.g.println token) instead of accessing it via the JMeter variables object (vars.get("token")).NullPointerException:vars.get("name")returnednullbecause the variable was never created or an upstream extractor failed to find a match.Compilation Cache Full/ High CPU: Script text contains\${var}string interpolation instead of usingvars.get("var").
Essential JSR223 Implicit Objects Reference
Section titled โEssential JSR223 Implicit Objects ReferenceโJMeter automatically injects predefined context objects into Groovy scripts:
| Object | Class | Scope & Purpose |
|---|---|---|
vars | JMeterVariables | Thread-scoped read/write (vars.get("k"), vars.put("k", "v"), vars.putObject("k", obj)) |
props | JMeterProperties | Global cross-thread properties (props.get("p"), props.put("p", "v")) |
prev | SampleResult | Previous sampler result (prev.getResponseDataAsString(), prev.setSuccessful(false)) |
sampler | Sampler | Current sampler object (sampler.setName("New Name")) |
ctx | JMeterContext | Engine context (ctx.getThreadNum(), ctx.getPreviousResult()) |
log | Logger | Log4j2 logger (log.info("msg"), log.error("err", exception)) |
Fix (ordered)
Section titled โFix (ordered)โ1. Always Use vars.get() and vars.put() (Never Direct Variables)
Section titled โ1. Always Use vars.get() and vars.put() (Never Direct Variables)โIn Groovy, JMeter variables are not global script variables. Always access them via the vars object:
// โ WRONG: Throws MissingPropertyException if not declared in scriptString myId = userId;
// โ WRONG: String interpolation breaks compilation caching and leaks Metaspace!String myId = "${userId}";
// โ
CORRECT: Safe retrieval with null checkingString myId = vars.get("userId");if (myId != null) { vars.put("processedUserId", myId.trim().toUpperCase());} else { log.warn("Variable 'userId' was null! Upstream extractor may have failed.");}2. Defensively Handle Null Values
Section titled โ2. Defensively Handle Null ValuesโIf an upstream JSON Extractor or Regex Extractor fails, vars.get() returns null. Add safe navigation (?.) or explicit null guards:
// Using Groovy safe navigation operatorString rawResponse = prev?.getResponseDataAsString();
String authToken = vars.get("authToken");if (!authToken) { // Fail the sample deliberately with a clear error message prev.setSuccessful(false); prev.setResponseMessage("Missing required authToken from previous step"); prev.setResponseCode("500"); return;}3. Share Data Between Different Thread Groups with props
Section titled โ3. Share Data Between Different Thread Groups with propsโvars are strictly isolated per thread. If Thread Group A extracts a token needed by Thread Group B, use props:
// In Thread Group A (Writer)props.put("GLOBAL_AUTH_TOKEN", vars.get("authToken"));
// In Thread Group B (Reader)String globalToken = props.get("GLOBAL_AUTH_TOKEN");vars.put("localToken", globalToken);4. Enable Script Caching
Section titled โ4. Enable Script CachingโIn every JSR223 component:
- Ensure Language is set to
groovy. - Check Cache compiled script if available.
- Do not put dynamic values in the script body; use
vars.get()or script Parameters:- Parameters:
\${__threadNum} \${userId} - Script access:
String p0 = args[0];
- Parameters:
5. Parse JSON and XML Safely with Groovy Builders
Section titled โ5. Parse JSON and XML Safely with Groovy BuildersโUse built-in Groovy parsers instead of manual regex string manipulation:
import groovy.json.JsonSlurperimport groovy.json.JsonOutput
try { def json = new JsonSlurper().parseText(prev.getResponseDataAsString()) String itemId = json.data.items[0].id vars.put("firstItemId", itemId)} catch (Exception e) { log.error("Failed to parse JSON response: " + e.getMessage(), e) prev.setSuccessful(false)}Related tools and topics
Section titled โRelated tools and topicsโ| Resource | Use when |
|---|---|
| Metaspace & GC overhead | Fixing Metaspace leaks caused by Groovy scripts |
| Functions and variables | Built-in JMeter functions guide |
| Correlation & dynamic values | Extracting and passing dynamic values |
| Best practices | Scripting language performance recommendations |
Frequently asked questions
Section titled โFrequently asked questionsโShould I use BeanShell or Groovy for scripting in JMeter?
Section titled โShould I use BeanShell or Groovy for scripting in JMeter?โAlways use Groovy (JSR223). Groovy compiles down to native Java bytecode and supports script compilation caching, making it 10x to 50x faster than BeanShell. BeanShell is deprecated for high-load testing.
Why do my changes to vars not appear in other threads?
Section titled โWhy do my changes to vars not appear in other threads?โvars (JMeterVariables) are local to the current thread. To pass data across threads, use props.put("key", value) and props.get("key").