bblimke/webmock · error · RuntimeError
Invalid WebMock stub declaration. times(N) can be declared o
Error message
Invalid WebMock stub declaration. times(N) can be declared only after response declaration.
What it means
times() repeats the last response sequence (responses_sequences.last), so at least one response declaration (.to / .then) must already exist on the stub; otherwise RuntimeError 'Invalid WebMock stub declaration...' is raised. This is a DSL-ordering guard - before a .to call there is nothing to repeat.
Source
Thrown at lib/webmock/request_stub.rb:101
@responses_sequences.shift if @responses_sequences.first.end?
@responses_sequences.first.next_response
else
@responses_sequences[0].next_response
end
end
def has_responses?
!@responses_sequences.empty?
end
def then
self
end
def times(number)
raise "times(N) accepts integers >= 1 only" if !number.is_a?(Integer) || number < 1
if @responses_sequences.empty?
raise "Invalid WebMock stub declaration." +
" times(N) can be declared only after response declaration."
end
@responses_sequences.last.times_to_repeat += number-1
self
end
def matches?(request_signature)
self.request_pattern.matches?(request_signature)
end
def to_s
self.request_pattern.to_s
end
def self.from_request_signature(signature)
stub = self.new(signature.method.to_sym, signature.uri.to_s)
if signature.body.to_s != ''View on GitHub (pinned to b187df8827)
Solutions
- Declare the response first, then repeat: stub_request(:get, 'www.example.com').to(body: 'ok').times(3)
- For multiple sequences chain .to(r1).then.to(r2).times(2) - times always applies to the last declared response
- If the stub needs no response yet, still declare .to(something) before times, or drop times entirely
Example fix
// before stub = stub_request(:get, 'www.example.com') stub.times(3) # => RuntimeError: Invalid WebMock stub declaration... // after stub = stub_request(:get, 'www.example.com').to(body: 'ok') stub.times(3)
Defensive patterns
Strategy: try-catch
Try / catch
begin
stub.times(3)
rescue RuntimeError => e
raise unless e.message.include?('declared only after response declaration')
stub.to(body: 'ok').times(3) # attach a response first, then repeat
end Prevention
- Keep .to(...).times(n) on one chained line so ordering is visible
- Treat .then as the separator between response sequences; times always follows a .to
- In stub builder helpers, attach all responses before applying any times modifier
When it happens
Trigger: stub_request(:get, 'www.example.com').times(3) with no .to anywhere; splitting a stub across lines and calling times before to: stub.times(2).to(body: 'x'); refactors or helper methods that attach responses conditionally after times.
Common situations: Copy-pasting DSL examples and dropping the .to line; builder helpers that call times before responses are attached; misunderstanding that times binds to the preceding response declaration only.
Related errors
- #to_return_json does not support passing a block
- Wrong order. Use :before_local_stubs or :after_local_stubs
- times(N) accepts integers >= 1 only
- Real HTTP connections are disabled. Unregistered request: #{
- #with method invoked with no arguments. Either options hash
AI-assisted analysis of bblimke/webmock@b187df8827 (2026-08-23).
Data as JSON: /api/errors/4d52730555dbd863.
Report an issue: GitHub.