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

  1. Declare the response first, then repeat: stub_request(:get, 'www.example.com').to(body: 'ok').times(3)
  2. For multiple sequences chain .to(r1).then.to(r2).times(2) - times always applies to the last declared response
  3. 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

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


AI-assisted analysis of bblimke/webmock@b187df8827 (2026-08-23). Data as JSON: /api/errors/4d52730555dbd863. Report an issue: GitHub.