Functions, Custom Properties, Reusable Fragments, and Modular Plans: Diagnostics, Failure Modes, and Production Practices
Modularity failures often happen before the target receives any traffic. A plan can fail because the Include file cannot be found, a Module reference resolves to the wrong duplicate controller, or a missing property silently defaults to one. The correct diagnostic response is to preserve path/property/tree evidence and find the failing layer—not to add retries, threads, heap, or server-side changes.
Learning objectives
-
Diagnose an Include path failure from
jmeter.logand command manifest. -
Recognize hidden
__Pdefaults that alter configured load. - Repair duplicate fragment/controller naming.
- Reject global mutable properties for per-user state.
- Prevent redundant/circular module dependencies and non-replayable random inputs.
- Distinguish path/config/generator failures from target latency/saturation.
1. Preserve first-failure evidence
127.0.0.1:8020, ≤2
threads ×3 work loops.
Preserve failed JMX, fragment/property files, cwd/project
root/include prefix, command manifest, JTL if created,
jmeter.log, generator state and fixture event/stats
evidence before repair. Never redirect a broken plan to production
“to see if it works there.”
2. Diagnostic sequence
Modularity changes where configuration is defined, not the fundamental JMeter execution model. Properties/functions resolve configuration, controllers assemble reusable elements, and the resulting samplers still execute inside ordinary JMeter threads against the same authorized target.
flowchart TD E[Preserve JTL / jmeter.log / command manifest / target events] --> V[Confirm JMeter + Java + tool versions] V --> C[Confirm exact JMX / fragments / properties / CLI + authorized target] C --> R[Resolve cwd / user.dir / project root / include prefix / filenames] R --> S[Validate runtime tree scope + unique module names + resolved vars/properties] S --> P[Inspect per-thread session/data state] P --> G[Inspect generator JVM / OS / filesystem / network] G --> T[Inspect SUT telemetry / received event counts] T --> X[Inspect distributed / CI / container checkout/path state if relevant] X --> F[Least destructive correction] F --> M[Small controlled rerun and compare]
3. Intentionally broken example: direct Include run without prefix
main-include.jmx contains:
Include Controller — INC.session.bootstrap.v1
Filename: session-bootstrap.jmx
The fragment actually lives in sibling directory
fragments/, not plans/. From an unrelated
working directory, deliberately bypass the launcher and omit
includecontroller.prefix:
Set-Location "$env:TEMP"
& "$env:JMETER_HOME\bin\jmeter.bat" `
-n `
-t "F:\Labs\p20-modular-lab\plans\main-include.jmx" `
-q "F:\Labs\p20-modular-lab\config\local.properties" `
-Jrun.id=p20-broken-path `
-Jvariant=include-broken `
-l "F:\Labs\p20-modular-lab\results\broken\results.jtl" `
-j "F:\Labs\p20-modular-lab\results\broken\jmeter.log"
Expected: JMeter cannot resolve the intended external fragment via
prefix+Filename and fallback to the JMX launch directory also does
not find session-bootstrap.jmx. Preserve the log. The
fixture should see no valid session/work sequence for that failed
run.
Repair: run through
tools/run-local.ps1, which supplies the absolute
-Jincludecontroller.prefix=.../fragments/. Keep JMX
filename unchanged and rerun the smallest 1-thread profile first.
5. Failure mode: function-heavy unreadable fields
Anti-pattern:
${__P(run.id,${__time(YMDHMS)})}-${__threadNum}-${__Random(1,9999)}-${__UUID()}
This hides fallback-to-current-time, thread identity, two kinds of randomness and replay semantics inside one field. Split named values into clear properties/variables/functions, and use deterministic data when replay matters.
6. Failure mode: duplicate fragment/controller names
Module Controller resolves fragments by controller/parent names. Two
generic Simple Controller or two identical
FRAG.session.bootstrap.v1 paths can make the module
reference ambiguous/wrong after reload.
Repair: give each reusable controller a unique hierarchical name and reopen/reselect the Module Controller target. Also give multiple Include Controllers that include the same file distinct controller names, per current JMeter guidance.
7. Failure mode: global mutable property for per-user session
Broken:
${__setProperty(SESSION_ID,${SESSION_ID})}
...
/work?session_id=${__P(SESSION_ID)}
Properties are global to the JMeter process. Thread 2 can overwrite Thread 1's session before Thread 1 sends work. In distributed testing, each engine also has a different “global” property universe.
Repair: keep SESSION_ID in the extractor-created
thread-local variable and reference
${SESSION_ID} directly.
8. Failure mode: circular/redundant module structure
An external fragment includes another fragment that eventually points back to the first, or a main plan includes the same setup at two levels. Even where parsing/loading prevents a literal infinite cycle, the design is invalid because runtime ownership and operation counts are no longer obvious.
Maintain an acyclic dependency graph with one owner for each reusable behavior. Flatten redundant wrapper fragments that add no contract.
9. Failure mode: random functions without replay strategy
A failing run used __Random for business data but did
not record generated values or a seedable mechanism. The next run
cannot reproduce the same input.
Repair: use seeded Random Variable where appropriate, generated/committed deterministic fixtures, or persist the generated values in result/sample variables if exact replay is required. Use random functions only when randomness itself is part of the workload model.
10. Failure mode: “works in GUI” cwd assumptions
GUI launch from the project root can hide path assumptions. A scheduler, CI runner, IDE or shell may start from another directory. Always test a clean-shell invocation from a different cwd using the project launcher before declaring the module portable.
11. Failure mode: putting top-level configuration in included JMX
Cookie Manager or User Defined Variables inside the external included file are not guaranteed to work as expected. Keep shared configuration at the top-level plan and let the fragment accept those already-resolved settings.
12. Causal symptom table
| Symptom | Likely modular/generator cause | Target cause to distinguish | Evidence |
|---|---|---|---|
| No target traffic; include error | filename/prefix/JMX launch path | target outage | jmeter.log + command manifest + target zero events. |
| Run unexpectedly uses 1 thread | missing __P property/default |
server capacity change | resolved properties + JTL thread count. |
| Wrong session appears across users | global property/shared state | server session corruption | vars/props config + target session/thread events. |
| Different CI behavior | checkout/cwd/module/property file missing | target regression | CI cwd/files/manifest + target event equality. |
| Throughput lower after modularization | extra duplicated runtime invocation/path/log overhead | target slowdown | JTL sample counts + runtime tree + target service time + generator CPU. |
| Cannot reproduce failed data | unseeded/unrecorded randomness | intermittent target bug | input evidence/seed/manifest. |
13. Security-sensitive boundaries
Property files, launchers and manifests can accidentally capture credentials/environment variables. Include files can execute arbitrary samplers/processes if sourced from an untrusted repository. Treat JMX/fragments/scripts as executable test code. Keep real secrets outside versioned files/logs, validate module provenance, and use only disposable authorized targets.
14. Troubleshooting shortcuts to reject
- Do not add blanket retries or arbitrary sleeps around include/module errors.
- Do not increase heap or threads to “push through” path/property failures.
- Do not disable listeners wholesale without evidence.
- Do not mutate process-global properties to synchronize virtual users.
- Do not disable TLS/RMI verification.
- Do not switch to a production target when a local module fails.
- Do not grow a recursive module graph to avoid naming a clear boundary.
-
Do not delete failed JTL/
jmeter.log/manifest evidence.
Knowledge check
What evidence proves an Include failure happened before the SUT?
jmeter.log/path evidence shows the fragment was not loaded and the fixture has no matching session/work events.
Why can __P(threads) create a false-green run?
A missing property defaults to 1, so the plan can complete successfully with less load than intended.
Why can't properties safely hold per-user SESSION_ID?
They are shared across threads in one JMeter JVM and can overwrite another user's state.
How should a random-data failure become reproducible?
Use a seeded mechanism or preserved deterministic/generated input manifest rather than unrecorded randomness.
What is the least-destructive repair for the broken Include example?
Supply the correct resolved includecontroller.prefix via the launcher; do not rewrite target/load or hide the error.
Official references and version notes
- JMeter Component Reference — Module Controller — runtime substitution of an already loaded controller/fragment and unique fragment naming.
-
JMeter Component Reference — Include Controller
— external JMX/Test Fragment use, filename limitations,
includecontroller.prefix, and path fallback behavior. - JMeter Component Reference — Test Fragment — reusable fragment semantics with Module/Include Controllers.
- JMeter Functions — __P — simplified command-line property lookup and default behavior.
- JMeter Functions — __property — general JMeter property lookup and optional variable assignment.
- JMeter Functions — __threadNum — thread-group-local thread numbering and Configuration Element restrictions.
- JMeter Functions — __Random — pseudo-random values and optional variable assignment.
- JMeter Component Reference — Random Variable — seeded/per-thread reproducible random-number option.
-
JMeter Getting Started
—
-q/-J, property files, and JMeter configuration loading. - JMeter Best Practices — GUI authoring/debugging and non-GUI execution for load.
- Apache JMeter downloads — current stable release and Java requirement.
Version-sensitive statements were rechecked against current Apache
JMeter primary documentation on 2026-09-05. The course baseline
remains Apache JMeter 5.6.3 with a Java 17 JDK;
JMeter 5.6.3 requires Java 8+. A Module Controller substitutes an
already loaded controller/fragment into the active runtime path;
fragments referenced by Module Controller need unique names
because JMeter uses the controller/parent name path to find them
after reload. Include Controller is for external JMX/Test Fragment
content. Its Filename field does not support
variables/functions. The
includecontroller.prefix property can prefix the
filename; if prefix+filename cannot be found, JMeter attempts the
filename relative to the JMX launch directory. Top-level Cookie
Manager/User Defined Variables belong in the main test plan rather
than an included JMX because included copies are not guaranteed to
work as expected. __P(name,default) is intended for
command-line properties; without an explicit default it returns
1. __threadNum is local to its Thread
Group and should not be placed in Configuration Elements such as
User Defined Variables because those are processed by a separate
thread. For reproducible random numeric data, the Random Variable
Config Element exposes a seed/per-thread option; the simple
__Random function does not expose an equivalent seed
parameter.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.