bblimke/webmock · error · RuntimeError
Invalid WebMock stub declaration. times(N) can be declared…
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.
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
- times(N) accepts integers >= 1 only
- #to_return_json does not support passing a block
- Wrong order. Use :before_local_stubs or :after_local_stubs
- Can't convert # into Hash.
- Invalid JSON string: #
AI-assisted analysis of bblimke/webmock@b187df8827 (2026-08-23).
Data as JSON: /api/errors/4d52730555dbd863.
Report an issue: GitHub.
Appendix: 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)