skip to content

In JMeter, what happens when two HTTP Header Managers are in one sampler's scope?

level: middleimportance: should knowfreq 47%

answer

  1. Managers do not all behave the same way
  2. Entries are combined, not discarded
  3. Collisions are decided by name, ignoring case
  4. The nearer element to the sampler holds

basics

~20 s

JMeter merges them into one header list for that sampler. Where both define the same header name, the manager nearer the sampler keeps its value, and the outer one contributes only the names the inner one does not set.

solid answer

~50 s

The HTTP Header Manager is the exception among JMeter's managers: multiple Header Managers in a sampler's scope are **merged**, not chosen between. The component reference says so directly — "JMeter now supports multiple Header Managers. The header entries are merged to form the list for the sampler" — and the merge is name-based and case-insensitive. In Apache JMeter 6.0.0 the sampler collects config elements innermost-first, so on a name collision the manager nearest the sampler is the one whose value survives; the outer manager only adds header names the inner one has not defined. That is what makes the documented pattern work: a broad Header Manager high in the tree supplies a default set, and a Header Manager under one request adjusts a couple of entries without having to restate the rest. Note that an empty value replaces a header's value rather than removing the header.

code

xml · 12 lines
xml
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="Plan defaults" enabled="true">
  <collectionProp name="HeaderManager.headers">
    <elementProp name="Accept" elementType="Header">
      <stringProp name="Header.name">Accept</stringProp>
      <stringProp name="Header.value">*/*</stringProp>
    </elementProp>
    <elementProp name="Content-Type" elementType="Header">
      <stringProp name="Header.name">Content-Type</stringProp>
      <stringProp name="Header.value">application/xml</stringProp>
    </elementProp>
  </collectionProp>
</HeaderManager>

go deeper

for a junior

Know that a Header Manager applies to every sampler under its parent, and that adding a second one nearer a request adjusts headers rather than replacing the whole set.

for a middle

Explain the merge: entries are combined by header name, the comparison ignores case, and the manager closest to the sampler keeps its value when both define the same name.

for a senior

Recognise the failure in the field — a header appearing on samplers that show no Header Manager of their own — and fix it by moving the element down rather than by editing values.

for a principal

Decide the team's convention for shared headers: a small, genuinely universal default set high in the tree, with per-flow adjustments attached to the controller that owns the flow, so scope is legible in review.

## Managers are not all alike JMeter's scoping rules carry a note that the Header Manager, Cookie Manager and Authorization Manager are treated differently from the Configuration *Defaults* elements, and that when more than one Manager is in a sampler's scope only one is used. For the Cookie and Authorization Managers that is exactly right. For the **HTTP Header Manager** it is not: the component reference for that element, in the same 6.0.0 manual, states that multiple Header Managers are supported and their entries are merged to form the list for the sampler, and the sampler code merges them. Read the component page for the Header Manager, not the general note. ## What the merge actually does When the engine configures a sampler it hands over every config element in scope. The HTTP sampler treats a Header Manager specially: if it already holds one, it merges the new one into it rather than overwriting. The merge walks the incoming manager's entries and adds only those whose **name** does not already exist in the accumulated list, comparing names case-insensitively — so `Content-Type` and `content-type` are the same entry. Because config elements are gathered from the sampler outwards — the sampler's own children first, then its parent's, up to the Test Plan — the first manager into the accumulator is the innermost one. The practical rule: - **Nearest manager wins a name collision.** A `Content-Type` set under the request beats a `Content-Type` set under the Thread Group. - **Outer managers contribute only new names.** Everything the inner one does not mention still arrives. - **Nothing is removed.** An empty value replaces the value of a header; it does not delete the header. | Attached at | Headers it defines | Sent by the request | | --- | --- | --- | | Thread Group | `Accept: */*`, `Content-Type: application/xml` | `Accept: */*` | | That request | `Content-Type: application/json` | `Content-Type: application/json` | ## The header manager one level too high The common failure is the mirror image: a Header Manager attached one level *above* where it belongs. Someone adds a Header Manager under the Thread Group to set `Content-Type: application/json` for the two API calls in the plan, and every sampler in the group now sends it — the static-asset fetches, the health check, the form post that needs `application/x-www-form-urlencoded`, and anything a colleague adds to the group next month. The symptom rarely looks like a header problem. It shows up as a subset of requests returning 415 or 400 while the same requests pass by hand, or as a service quietly taking a different code path. The tell is that the offending header appears on samplers whose GUI shows no Header Manager at all, because the element that supplied it is a level up. There are two clean fixes, and one that only looks clean: 1. **Move it down.** Attach the Header Manager under the samplers, or under the controller wrapping the flow, that genuinely need it. Scope becomes visible in the tree. 2. **Override at the request.** Leave the broad manager in place and add a Header Manager under the request that needs something else, setting the same header name. The merge gives the inner one the collision, so the request sends what it asked for. 3. **Blank out the value at the request.** This does not work the way people expect: an empty value replaces the value, it does not remove the header, so the request still carries the name. ## Two details worth knowing The merged manager is rebuilt each time the sampler is configured — the HTTP sampler clears its header-manager property before each configuration pass, precisely so repeated loop iterations do not keep merging and re-merging the same elements into an ever-growing list. And when debug logging is on, the merged element is named after the pair it came from, joined by a colon, which is a quick way to confirm from the log that two managers really were in scope. ## Distinguishing this from the other managers | Element | Two in one sampler's scope | | --- | --- | | HTTP Header Manager | merged; nearest wins a name collision | | HTTP Cookie Manager | one is used; the manual says there is no way to specify which | | HTTP Authorization Manager | one is used; likewise unspecified | If you remember only one thing, remember that the Header Manager is the one that composes and the others are the ones that do not — and that composing is a feature you can lean on deliberately, not an accident to be avoided.

  • How would you stop one request from sending a header that a Header Manager higher in the tree defines?
    Move the broad Header Manager down so that request is no longer in its scope, or attach a Header Manager under the request and give the same name a different value, which wins the collision. Setting the value to empty does not help — an empty value replaces the value and leaves the header name in place.
  • Does the same merge behaviour apply to two HTTP Cookie Managers in scope?
    No. The manual states that if more than one Cookie Manager is in a sampler's scope there is no way to specify which one is used, and cookies stored in one manager are not visible to the other. The Header Manager is the manager that composes; Cookie and Authorization Managers are not merged.

saying these in an interview costs you the question

  • Says the outermost Header Manager always wins
  • Thinks only one Header Manager in scope is used
  • Expects an empty header value to delete the header
  • Assumes header names are matched case-sensitively
  • Blames the sampler when a header comes from a level above