skip to content

In a Karate feature file, what does `* configure retry = { count: 10, interval: 500 }` change, and what happens if you write `* configure retry = 10` instead?

level: middleimportance: should knowfreq 46%

answer

  1. two numbers, not a switch
  2. three attempts, three seconds
  3. the sub-keys are independent
  4. the value has to be a map

basics

~10 s

It changes the defaults a retry until step polls with: attempts and milliseconds between them, replacing the built-in 3 and 3000. A bare number is silently ignored, because the value must be a map.

solid answer

~40 s

`configure retry` carries the polling defaults for Karate's `retry until` step: `count` is the number of attempts and `interval` is the wait between them in milliseconds. The built-in values are **count 3** and **interval 3000**, and the two keys are merged independently — `{ interval: 100 }` leaves the count at 3. The value **must be a map**. The key itself is recognised, so `* configure retry = 10` does not throw, but the value fails the map check and is discarded: the defaults stay at 3 and 3000 and nothing is logged. That silent no-op is the trap in this step. Like any `configure`, its reach is decided by where you put it — config file, `Background`, or one scenario.

code

gherkin · 10 lines
gherkin
Feature: retry defaults

Scenario: change both numbers
  * configure retry = { count: 5, interval: 0 }

Scenario: change only the interval - count stays at 3
  * configure retry = { interval: 100 }

Scenario: silently does nothing - the value is not a map
  * configure retry = 10

go deeper

for a junior

Remember the shape and the defaults: a map with count and interval, defaulting to 3 attempts and 3000 ms. A bare number is not a valid value.

for a middle

Explain that the two sub-keys merge independently and that a non-map value is discarded without an error, so the symptom is a poll that ends early rather than a failing step.

for a senior

Treat a widened retry as a signal. Ten attempts hiding a race reads the same as ten attempts modelling a genuinely eventual API, and only the second one belongs in the suite.

for a principal

Decide where polling budgets are allowed to be set and who owns the worst-case suite runtime, since count times interval multiplied across a large pack is a pipeline-duration decision.

## What the key holds `configure retry` does not retry anything by itself. It stores two numbers that Karate's `retry until` step reads when it polls: | sub-key | meaning | default | |---|---|---| | `count` | how many attempts before giving up | 3 | | `interval` | milliseconds to wait between attempts | 3000 | So out of the box a `retry until` polls three times with three seconds between them. `configure retry = { count: 10, interval: 500 }` changes that to ten attempts half a second apart for every `retry until` in the configure's scope. ## The two sub-keys are independent The implementation reads `interval` and `count` separately and only overwrites the one that is present. `configure retry = { interval: 100 }` therefore leaves `count` at 3, and `configure retry = { count: 20 }` leaves `interval` at 3000. Karate's own examples use exactly these partial forms, so the merge is the intended behaviour rather than an accident. This is worth stating explicitly in review, because the total wall-clock budget is the product of the two and it is easy to change one and reason about the other from memory. Twenty attempts at the default interval is a minute; twenty at 200 ms is four seconds. ## The value must be a map, and a non-map is silently dropped This is the part that catches people. The key switch recognises `retry`, so nothing throws. Inside that branch, though, the value is checked for being a map before either sub-key is read. A number, a string or a boolean fails that check and the branch simply does nothing: - `* configure retry = 10` runs green and leaves the defaults at 3 and 3000; - so does `* configure retry = '10'`; - and nothing is logged on that path, so there is no breadcrumb in the report. The symptom is a `retry until` that gives up far sooner than the author intended, usually reported as flakiness rather than as a configuration bug. Contrast this with an unknown key, which is loud: `configure retrys = {...}` throws `unexpected 'configure' key: 'retrys'`. Karate is strict about key names and lenient about value shapes, and that asymmetry is exactly what makes this one hard to spot. ## Scope, as with every configure key `configure retry` follows the same placement rules as the rest of the family: 1. In `karate-config.js` via `karate.configure('retry', {...})` — applies wherever that config reaches. 2. In a `Background` — re-applied before every scenario in the feature. 3. Inside a scenario — from that step to the end of that scenario. A scenario that needs one unusually patient poll should configure it locally rather than raising the number for everything, so the exception stays visible next to the call it belongs to. ## What this question is not about It is worth separating the mechanism from the judgement. Whether a given call *deserves* a retry at all, and how long a wait is reasonable, are test-design decisions that belong to the discipline of automated testing rather than to Karate. The mechanism is what interviewers probe here: which keys exist, what the defaults are, what shape the value has to be, and what happens when it is the wrong shape. ## What it is not: transport-level retries A separate key, `httpRetryEnabled`, controls whether the underlying HTTP client retries automatically when a request fails at the transport level. It is a boolean, it defaults to **false**, and Karate explicitly disables the client's automatic retries when it is off. That is a different mechanism from `configure retry`: - `configure retry` supplies the numbers a `retry until` step polls with, and polling means re-sending the request and re-evaluating a condition you wrote; - `httpRetryEnabled` hands the decision to the HTTP client, which knows nothing about your condition and retries on its own criteria. Neither of them retries a **failed assertion**. A `match` that fails ends the scenario; nothing in the `configure` family re-runs it. Candidates who reach for `configure retry` to make a flaky assertion pass have the wrong mechanism as well as the wrong instinct. ## A checklist for reviewing a retry configuration - Is the value a map? A bare number is a silent no-op. - Is only one sub-key set, and is the other one still the default you expect? - Multiply `count` by `interval` — is that worst-case wait acceptable on every call in scope? - Is the configure placed as narrowly as the need? A patient poll in the config file makes every failing call in the suite slow. - Does the surrounding scenario still assert something meaningful, or has the retry been widened until the assertion cannot fail?

  • If a Karate scenario sets `configure retry = { interval: 100 }` and nothing else, how many attempts does a `retry until` make?
    Three, the built-in default. The two sub-keys are read independently and only the one present in the map is overwritten, so setting `interval` alone leaves `count` untouched. The practical effect is a poll that finishes in about 200 ms of waiting rather than the 6 seconds the defaults give — often the opposite of what the author intended when they lowered the interval to make polling tighter.
  • Why does a wrong key in a Karate `configure` step throw while a wrong value type often does not?
    Key matching is a switch with no permissive default, so anything unrecognised raises `unexpected 'configure' key: '<key>'`. Values are handled inside each key's own branch, and several branches guard on the expected shape and simply return when it does not match — `retry` is the clearest example. The design catches typos immediately but leaves type mistakes to show up later as behaviour, which is why the map requirement is worth remembering.

saying these in an interview costs you the question

  • Says a bare number assigned to configure retry sets the attempt count
  • Thinks configure retry makes failed HTTP calls retry on its own
  • Believes interval is expressed in seconds
  • Assumes a partial map resets the sub-key it omits to zero
  • Expects a wrong value type to raise an error like a wrong key does