Chapter 5: Correlation and Parameterization
Let me be honest -- you will spend more time debugging correlation than writing it. When things go wrong (and they will), having a systematic approach saves hours of frustration. Here is the playbook I use, developed from years of "why is this not working?!" moments.
The Debug Sampler is a special JMeter sampler that outputs all current JMeter variables and their values. Add it after the request with the extractor, run the test, and check its output in View Results Tree. You can see every variable, every value, and immediately spot what went wrong.
# Add: Thread Group > Add > Sampler > Debug Sampler
# Settings:
# JMeter properties: False (too noisy)
# JMeter variables: True (this is what you want)
# System properties: False (not relevant)
# Place it AFTER the request with the extractor:
# GET /login
# └── Regular Expression Extractor (csrf_token)
# Debug Sampler <-- here
# POST /login
# Run the test and check View Results Tree for the Debug Sampler.
# Its Response Body shows ALL variables:
# auth_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# cart_id=NOT_FOUND
# csrf_token=xK9mP2nQ
# password=Priya@123
# product_id_1=P001
# product_id_2=P002
# product_id_matchNr=2
# username=priya.sharma@test.com
# You can immediately see:
# - csrf_token was extracted successfully
# - cart_id is NOT_FOUND (extraction failed or not yet executed)
# - CSV variables are populated correctly
# - product_id extracted 2 matches| Symptom | Cause | Fix |
|---|---|---|
| Variable shows default value (NOT_FOUND) | Regex/JSONPath does not match the response | Check actual response in View Results Tree. Pattern may be wrong or value is in headers, not body |
| Variable is empty (blank) | No default value set and no match found | Set a default value to distinguish "no match" from "empty match" |
| Wrong value extracted | Match No. is incorrect or regex is too greedy | Use Match No. = 1 for first occurrence. Use non-greedy (.+?) instead of (.+) |
| Works on first run, fails on second | Variable from previous iteration is being reused | Set default value -- JMeter keeps old variable values if extraction fails |
| 403/401 despite correct extraction | Token expires between requests (test too slow) | Reduce think times or add a token refresh mechanism |
| All threads get same CSV row | Sharing mode is "Current thread" instead of "All threads" | Change CSV Data Set Config sharing mode to "All threads" |
| CSV variables are header names | "Ignore first line" is set to False | Set "Ignore first line" to True if your CSV has headers |
| CSV shows wrong columns | Variable names do not match column count or delimiter is wrong | Check delimiter setting and ensure variable name count matches column count |
| Extractor works in GUI but not CLI | Different response in non-GUI mode (missing cookies/headers) | Add HTTP Cookie Manager and HTTP Header Manager. Verify server returns same response in both modes |
Run with 1 thread, 1 iteration in GUI mode with View Results Tree enabled
Click on the source request (the one with the extractor) in View Results Tree
Check the Response Body tab -- is the expected value actually present in the response?
If the value is not in the response: the problem is upstream (wrong URL, missing headers, failed auth)
If the value IS in the response: the problem is the extractor configuration
Add a Debug Sampler after the extractor and re-run -- check if the variable appears and what value it has
If variable shows default: the pattern does not match. Copy the exact text from the response and build your regex/JSONPath around it
If variable shows correct value but next request still fails: check you are using ${variable_name} in the right place (body, header, URL)
If it works with 1 thread but fails with multiple threads: check CSV sharing mode and think times
// Add after important extractors to create an audit trail
// This helps debug failures in non-GUI mode (command line)
def threadName = ctx.getThread().getThreadName()
def iteration = ctx.getVariables().getIteration()
def sampler = prev.getSampleLabel()
def responseCode = prev.getResponseCode()
// Log all correlation variables for this request
def correlationVars = [
"csrf_token", "auth_token", "user_id", "product_id", "cart_id"
]
def logLines = []
logLines.add("=== CORRELATION AUDIT: ${threadName}, Iteration ${iteration} ===")
logLines.add("Sampler: ${sampler}, Response Code: ${responseCode}")
correlationVars.each { varName ->
def value = vars.get(varName)
if (value == null) {
logLines.add(" ${varName} = NULL (not set)")
} else if (value.contains("NOT_FOUND")) {
logLines.add(" ${varName} = ${value} *** EXTRACTION FAILED ***")
} else {
// Truncate long values (like JWTs) for readability
def displayValue = value.length() > 50 ? value.substring(0, 50) + "..." : value
logLines.add(" ${varName} = ${displayValue}")
}
}
logLines.each { log.info(it) }Before a big load test run, always do a "dry run" with 1 thread and 2-3 iterations. Check every extractor by examining the Debug Sampler output. Fix all correlation issues with 1 thread before scaling up. Debugging with 500 threads is a nightmare -- debugging with 1 thread is straightforward.
Q: A recorded JMeter script works on the first replay but fails on the second. What is your debugging approach?
A: This is a classic correlation issue. My approach: (1) I add View Results Tree and run with 1 thread. (2) I compare the first run (success) with the second run (failure) -- specifically looking at response codes and response bodies. (3) I identify which request fails first -- this is the one that needs correlation from a previous response. (4) I look at the failing request body/headers for any hardcoded values that look dynamic (tokens, IDs, timestamps). (5) I search for those values in the responses of earlier requests. (6) Once found, I add the appropriate extractor (JSON Extractor for JSON, CSS Extractor for HTML, Regex for everything else) as a child of the source request. (7) I replace the hardcoded value with ${variable_name} in the failing request. (8) I add a Debug Sampler to verify the extraction. (9) I run 2-3 iterations to confirm it works across runs.
Key Point: Always debug with 1 thread first. Use the Debug Sampler to see all variables. Set meaningful default values so you can instantly identify which extraction failed.