skip to content

A JMeter Include Controller loads login.jmx but none of its samplers run. Why?

level: seniorimportance: should knowfreq 33%

answer

  1. The include is filtered, not pasted
  2. One element type anchors the file
  3. A warning, not a failure
  4. Only the first one counts

basics

~20 s

The included file almost certainly has no Test Fragment in it. An Include Controller keeps only the subtree under the first Test Fragment it finds, and when there is none it logs a warning and includes an empty tree.

solid answer

~40 s

An Include Controller does not paste the file in. After parsing it, `getProperBranch()` walks the loaded tree, descends through a Test Plan if it finds one, and returns the subtree of the **first `TestFragmentController`** it meets. Anything outside that fragment — a Thread Group, config elements at plan level, a second fragment — is discarded, and the manual says so for the Thread Group case: it "will be ignored during the include process". If no Test Fragment exists at all, the controller logs *"No Test Fragment was found in included Test Plan, returning empty HashTree"* and contributes nothing. Crucially it does not fail: the run continues a step short. It also calls `removeDisabledItems()` on what survives, so anything left disabled in the included file is stripped too.

code

text · 2 lines
text
2026-01-14 09:31:07,442 INFO o.a.j.c.IncludeController: loadIncludedElements -- try to load included module: /opt/jmeter/fragments/login.jmx
2026-01-14 09:31:07,461 WARN o.a.j.c.IncludeController: No Test Fragment was found in included Test Plan, returning empty HashTree

go deeper

for a junior

Know that the file an Include Controller reads must contain a Test Fragment, and that only what sits under that fragment is added to your plan.

for a middle

Explain the two passes over the loaded file: filter down to the first Test Fragment, then strip anything disabled. Everything outside the fragment, a Thread Group included, is thrown away.

for a senior

Diagnose it from evidence rather than by guessing: the log carries both the absolute path tried and the no-fragment warning, and the missing steps show as labels absent from the results, not as failures.

for a principal

Own the risk that this failure is silent. A shared fragment that stops contributing leaves three plans passing while testing less, so decide up front how a run proves the fragment's steps actually ran.

## What the controller keeps The Include Controller is a filter, not a paste. `IncludeController.loadIncludedElements()` parses the named `.jmx` with `SaveService.loadTree()` and then puts the result through two passes: 1. **`getProperBranch(tree)`** — iterate the top level; if a `TestPlan` is found, recurse into it; if a `TestFragmentController` is found, return **that node's subtree** and stop. If neither is found anywhere it reaches, log `No Test Fragment was found in included Test Plan, returning empty HashTree` and return an empty tree. 2. **`removeDisabledItems(tree)`** — recursively delete anything not enabled from what survived. So three separate things can leave you with an include that runs nothing: - the file has no Test Fragment at all; - the file has one, but the elements you care about are outside it; - the elements are inside it but left disabled. ## The symptom is quiet None of these is a run-stopping error. The warning goes to `jmeter.log` and the plan carries on: ``` 2026-01-14 09:31:07,442 WARN o.a.j.c.IncludeController: No Test Fragment was found in included Test Plan, returning empty HashTree ``` The same is true one step earlier, if the file cannot be opened at all: `loadIncludedElements()` catches the exception, logs, reports it, and returns nothing, and `JMeter.pConvertSubTree()` simply skips the replacement when the returned tree is null. The Include Controller then sits in the plan as an empty controller. That is worth contrasting deliberately with the other reuse mechanism. A Module Controller whose target cannot be resolved throws `JMeterStopTestException` and takes the whole run down. **The Include Controller degrades; the Module Controller stops.** When you inherit a plan, knowing which of the two you are looking at tells you whether silence is safe. ## The shape the file has to have The component reference gives the recipe: create a Test Fragment *underneath the Test Plan*, add samplers and controllers below it, save the plan, and that file is ready to include. For the login flow shared by three plans, the file looks like this: ``` login.jmx |- Test Plan |- Login Fragment <- Test Fragment: the only branch that is included | |- POST /login | `- Regular Expression Extractor: token `- Debug Thread Group <- ignored during the include `- Run Login <- Module Controller pointing at Login Fragment ``` That Thread Group is not a mistake. The manual explicitly suggests adding one "for debugging purposes", with a Module Controller referencing the Test Fragment, so the fragment can be exercised on its own; the include process throws it away. JMeter also gives you a way to produce this shape without hand-building it. The **Save as Test Fragment** action takes the nodes you have selected, creates a Test Fragment element, deep-clones the selection under it, and writes that to a file — which is exactly what the include expects to find. ## Traps around this - **Only the first fragment counts.** `getProperBranch()` returns as soon as it meets a `TestFragmentController`. A second Test Fragment in the same file is silently ignored, so one file means one includable fragment. - **Disabled elements inside the fragment vanish.** Somebody disabling one sampler "just for a local run" and committing it removes that step from all three plans. - **Plan-level state does not travel well.** The manual warns that a Cookie Manager or User Defined Variables belong in the top-level plan doing the including, not in the included file, or they "are not guaranteed to work". - **The shipped tutorial page is stale.** JMeter 6.0.0 still ships an *Include Controller Tutorial* describing a WorkBench and a Simple Controller as the file's root element. The WorkBench was dropped from the JMeter UI in 4.0, and a Simple Controller at the root is precisely the case that produces the empty-tree warning. The component reference and the code are the current contract. ## How to confirm it in a minute 1. Open `jmeter.log` and grep for `IncludeController`. The controller logs the absolute path it tried, plus either the no-fragment warning or a can't-load error. 2. Open the included `.jmx` in the GUI and check that a Test Fragment exists directly under its Test Plan and that everything you expect is nested inside it. 3. Check the enabled state of every element under the fragment. 4. Count the samplers in your results by label: an include that contributed nothing shows up as labels that never appear, not as failures.

  • What happens to a Thread Group inside the file a JMeter Include Controller loads?
    It is ignored. The controller keeps only the subtree under the first Test Fragment, so anything beside it is discarded. The manual actually suggests putting a Thread Group there on purpose, with a Module Controller referencing the fragment, so the fragment can be run and debugged on its own without affecting the plans that include it.
  • A JMeter Include Controller's file contains two Test Fragments. Which one is included?
    The first one the walk meets, and the second is dropped without a warning. The filter returns as soon as it finds a TestFragmentController. If you need both branches, split them into separate files with one fragment each, and give each plan its own Include Controller per file.
  • Does a JMeter Include Controller that cannot open its file stop the run?
    No. The load failure is caught, logged and reported, and the controller returns nothing, so the tree conversion simply leaves that branch empty and the test proceeds. That is the opposite of a Module Controller with an unresolved target, which throws a stop-test exception and shuts the run down.

saying these in an interview costs you the question

  • Says the whole included file is pasted into the plan
  • Expects a Thread Group in the included file to add threads
  • Thinks a missing Test Fragment fails the run
  • Assumes disabled elements in the included file still run
  • Believes several Test Fragments in one file are all included