Every iteration of a Postman run sends an identical X-Request-Id although the header is set to {{$guid}}. Why?
answer
- A generator that repeats was outranked
- Look for a dollar-prefixed key
- Defaults are reached only when unanswered
- Debugging residue in a shared scope
basics
~20 sSomething in the run holds a variable keyed literally $guid. Postman's dollar-prefixed generators are registered as substitution defaults consulted last, so that saved value answers the name first and the header repeats unchanged, with no error raised.
solid answer
~40 sA generator that stops generating almost always means it was **shadowed**. The SDK registers `$guid` and its siblings as substitution *defaults*, consulted **last**, so any variable the run holds under the key `$guid` answers first and every iteration substitutes that one saved value. Nothing errors, so the only evidence is the repeated header itself. Diagnose by listing the keys in every scope the run loads and looking for a dollar prefix — usually a fixed value someone pinned while debugging, or one that rode in with an imported set. Delete or rename that key, re-send twice, and confirm the value moves. Renaming the *token* is the wrong fix: the token spelling belongs to the SDK, the key is yours.
code
javascript · 6 linesconst seen = new Set();
pm.test('request id is unique across iterations', function () {
const id = pm.request.headers.get('X-Request-Id');
pm.expect(seen.has(id)).to.be.false;
seen.add(id);
});go deeper
Know the first check: if a generated placeholder stops changing, look for a saved variable whose key has the same dollar-prefixed name.
Explain why the saved value wins — the generators are registered as substitution defaults, so they answer only when nothing held answered first.
Demonstrate the diagnosis under production pressure: confirm the repeat client-side, scan scope keys for dollar prefixes, fix the source rather than your local copy.
Own the prevention: a silent collision needs a team convention around reserved key names plus a check that fails loudly when values a run assumes are unique repeat.
## The symptom A run makes many requests, each carrying a header whose value in the saved request is the token `{{$guid}}`. Every request that leaves the machine carries the *same* UUID. Nothing failed, nothing warned, and the request still looks dynamic when you open it. On the server side the effects arrive first: a uniqueness constraint starts rejecting the later requests, or an endpoint treating that header as an idempotency key keeps replaying the first result instead of doing new work. ## The mechanism behind it The collection SDK registers `$guid`, `$timestamp`, `$isoTimestamp` and `$randomInt` as **substitution defaults**, and defaults are consulted **last**. Substitution asks the variables the run actually holds before it reaches the default set. So if any scope in the run holds a key spelled literally `$guid`, that key answers the name and the generator is never invoked. The token resolves to one saved string, forever, and the run behaves exactly as if somebody had typed that UUID into the header by hand. Two properties make this a genuinely senior debugging problem rather than a trivia question: - **It is silent.** No error, no warning, no marker in the request or in the run output. The absence of a diagnostic is the whole difficulty. - **The cause is far from the symptom.** The key may live in a shared set that somebody else maintains, while the failure shows up as a server-side constraint violation in your pipeline. ## A diagnosis order 1. **Confirm the value repeats exactly.** A real generator effectively never emits the same UUID twice; one exact repeat is already conclusive. Compare the value that actually left the machine, not the token in the saved request. 2. **List the keys of every scope the run loads** and scan for a leading dollar sign. A dollar-prefixed key nobody deliberately created is the bug. 3. **Remove or disable that key** and send twice more. If the value starts moving, you are done; shadowing is not destructive, so the generator becomes reachable again immediately. 4. **Trace how the key got there** before closing the ticket — a pinned debugging value, an imported set carrying somebody else's key, or code that stored a captured value back under the name it had substituted. ## Ruling out the wrong theories | Theory | Why it does not hold | |---|---| | The runner caches resolved tokens | Each occurrence and each iteration is a separate evaluation; there is no cache of produced values | | The generator emits once per collection | Generation happens as each request is assembled, not once up front | | The braces are malformed | A malformed token is not substituted at all; here a value clearly arrives | | The server echoes a cached header back | The repetition is in what *left* the client, which client-side traffic confirms | Ruling these out matters, because each of them sends you looking at a component that is behaving correctly. ## Fixing it properly - **Change the key, not the token.** The spelling `$guid` belongs to the SDK; your variable's name is the part you control. Renaming it to something like `pinnedRequestId` keeps the pinned value if you still want it and frees the generator. - **If a fixed identifier was genuinely wanted,** keep it under a name of your own and reference that name in the header. Intent then reads off the request instead of hiding in a name collision. - **If the key rode in with a shared set,** fix it at the source. Deleting your local copy leaves the next person to rediscover it. ## Preventing the class of bug - Treat a leading dollar sign in a variable key as **reserved by convention**; the tool enforces nothing, so the team has to. - Review key lists in shared scopes the way you would review any other shared configuration — scanning for dollar prefixes costs seconds. - Where a run depends on values genuinely being unique, assert on that property rather than trusting it: if two requests in a run must not carry the same identifier, a check that notices the repeat turns a silent behavioural bug into a visible failure at the point it happens. - Prefer a small number of well-named pinned values over ad-hoc pinning during debugging, and remove them when the bug hunt ends. The generalisable point: when a *default* stops taking effect, the question is never whether the default broke. It is what got there first.
- What is the fastest way to prove the repeat is client-side rather than a server or proxy artefact?Compare the value that left the machine across two sends: inspect the outgoing header in the run's own record of the request. A repeat there proves substitution produced one value, so nothing downstream is involved and the search moves to the run's variable keys.
- Why is renaming the token, rather than the variable, the wrong fix?The token spelling is the SDK's — there is no alternative name for the generator, so renaming it just breaks the placeholder. The variable key is the part you own. Renaming or removing it resolves the collision and leaves the generator working for every other request too.
saying these in an interview costs you the question
- Blames a caching layer in the runner for the repeat
- Assumes the generator emits once per collection run
- Looks for malformed braces when a value clearly arrives
- Renames the token instead of the colliding variable key
- Deletes the local copy without fixing the shared source