A scenario run reports that two step definitions matched one step — what causes that and how do you fix it?
answer
- Two candidates, and no rule to choose
- Every loaded definition is a candidate
- Substrings match when nothing pins the ends
- The convenient wildcard collides with everything
- Fix the pattern set, not the sentence
basics
~20 sTwo loaded patterns both match that sentence — usually a duplicate definition, an unanchored expression matching a substring, or a catch-all wildcard. Fix the glue: delete the duplicate, anchor the pattern, narrow the wildcard. Never reword the scenario.
solid answer
~50 sAn ambiguous match is a defect in the glue layer, not in the product. Because binding is textual and every loaded definition is a candidate, more than one pattern can match the same sentence. The usual causes are a definition copied into a second glue file, an unanchored regular expression that matches the sentence as a *substring* of a longer one, a catch-all wildcard registered as a convenience, or two shared step libraries loaded together that both claim the phrase. Diagnose by having the runner report which patterns collided, then fix the pattern set: delete the duplicate rather than keeping both, anchor expressions at both ends, replace wildcards with typed placeholders, and scope which glue packages a run loads. Rewording the sentence is the tempting fix and the wrong one — it leaves both definitions registered, so the collision returns with the next author who writes that phrasing.
code
pseudocode · 7 lines# collides: matches the sentence as a substring
step(regex("a teacher opens the timetable"), openOwnTimetable)
step(regex("a teacher opens the timetable of another teacher"), openOtherTimetable)
# fixed: anchor both ends so each pattern owns one sentence
step(regex("^a teacher opens the timetable$"), openOwnTimetable)
step(regex("^a teacher opens the timetable of another teacher$"), openOtherTimetable)go deeper
Be able to say that the message means two patterns matched the same sentence and that the problem is in the glue, not in the product. Recognising a duplicated definition as the usual cause is enough here.
Explain the mechanics: unanchored expressions matching substrings, catch-all wildcards colliding with every later pattern, and two loaded libraries claiming a phrase. Say why load order is not an acceptable tie-breaker.
Show the diagnosis path — inspect what the run actually loaded, not the source tree — and treat rewording the specification as an unacceptable fix. Explain how ambiguity and undefined steps oscillate when the library is written per sentence.
Frame the phrase set as an interface with an owner. Be ready to decide whether a shared step library or team-local glue is the right default given how often collisions and cross-team breakage actually occur.
Ambiguity is the failure mode that follows directly from the glue layer's central design choice. Steps bind by text, every loaded definition is a candidate for every step, and nothing scopes a definition to the scenarios it was written for. So it is always possible for two registered patterns to match one sentence, and when they do the runner cannot choose — picking the first registered would make behavior depend on load order, which is worse than failing. It therefore reports an **ambiguous match** and names the colliding patterns. Runners differ in whether they fail only the affected scenario or abort the run, so do not assert one behavior as universal in an interview. ## The four common causes 1. **A duplicated definition.** Someone needed a step, could not find it, wrote it, and now two glue files register equivalent patterns. This is the most frequent cause and the easiest to miss, because the two files usually belong to different people. 2. **An unanchored regular expression.** A pattern written without start and end anchors matches the sentence as a substring. `a teacher schedules a lesson` then also matches `a teacher schedules a lesson and is notified`, colliding with the definition written for the longer sentence. Anchoring both ends is the standard hygiene rule for regular-expression-style patterns, and it is why higher-level step expressions, which anchor implicitly, remove a whole class of these. 3. **A catch-all wildcard.** A pattern with a match-anything segment — registered because it seemed to save work — collides with every narrower pattern anyone adds afterwards. The person who added the narrow pattern gets the failure, which makes the cause hard to trace back. 4. **Two libraries claiming the phrase.** When a suite loads a shared step library alongside its own glue, common phrasing collides. The shared library is often not the one that changes, so the fix is either to scope which packages the run loads or to accept the shared phrase and delete the local one. ## Diagnosis The report names both patterns and the file each was registered in, which is normally enough. Where it is not, the useful moves are the same as for any text-addressed lookup: list every registered pattern the runner loaded and search that list for the sentence rather than searching the source tree, because the collision is between *loaded* definitions and a run may load less, or more, than the repository contains. A run that suddenly reports ambiguity on an unchanged suite usually means **the set of loaded glue packages changed** — a new dependency, a widened package scan. ## Fixes, best to worst 1. Delete the duplicate and keep one owner for the phrase. 2. Anchor the expression at both ends. 3. Replace the wildcard with a typed placeholder so the pattern says what varies. 4. Narrow the loaded glue scope so unrelated libraries are not candidates. **The fix to reject** is rewording the scenario sentence so it only matches one pattern: it is fast, it makes the run go green, and it fixes nothing — both definitions are still registered, so the next person who writes the natural phrasing hits the same collision, and meanwhile the specification has been distorted to suit the glue. ## The neighbouring failure Ambiguity's opposite is the *undefined* step, where no pattern matched. The two failures pull in opposite directions and a library oscillates between them: - developers respond to undefined steps by adding definitions, which raises collision pressure; - and respond to ambiguity by broadening or renaming, which raises undefined pressure. The stable answer is neither — it is **one definition per behavior with the varying parts parameterized**, which is why ambiguity and glue design are really one topic. ## A worked example A school timetable planner suite gained a step for the sentence `a teacher opens the timetable of another teacher`, written to assert that the action is refused. A shared library already registered an unanchored pattern for `a teacher opens the timetable`, wired to open the teacher's *own* timetable. Before the collision surfaced, whichever pattern matched first quietly satisfied the new scenario, and a permission escalation — a teacher editing a colleague's timetable — sat behind a scenario that read as though it were being tested. When the second definition arrived, the run reported an ambiguous match, which is the useful outcome: the failure exposed both the collision and the fact that the escalation had never been asserted. Anchoring the shared pattern fixed the collision, and the narrow definition then owned the sentence it was written for.
- Why can't the runner just execute the first matching definition it finds?Because which one is first depends on load order, which depends on file system order, packaging and dependency resolution. The suite would then pass or fail differently on different machines for reasons no one can see in the scenario. Failing loudly on ambiguity turns a hidden nondeterminism into a fixable error.
- A suite that passed yesterday now reports ambiguity everywhere with no glue changes. Where do you look?At what the run loads, not at what the repository contains. A new or upgraded dependency that ships its own step library, or a widened package scan, adds candidate patterns without anyone editing a definition. Narrow the loaded scope, then decide which library should own the colliding phrases.
- Is an undefined step ever the safer failure to have?Yes, in the sense that it is unambiguous about what is missing: a sentence has no implementation and the runner says so. Ambiguity is worse to leave alone because until the second definition appeared, the wrong function may have been quietly satisfying scenarios that looked green.
saying these in an interview costs you the question
- Rewords the scenario sentence to dodge the collision
- Asks the runner to prefer the first registered pattern
- Blames the product for a glue-layer error
- Keeps both definitions and marks one as pending
- Writes regular-expression patterns without anchors
- Registers a match-anything wildcard as a convenience