{"record":{"id":"4d52730555dbd863","repo":"bblimke/webmock","slug":"invalid-webmock-stub-declaration-times-n-can-be","errorCode":null,"errorMessage":"Invalid WebMock stub declaration. times(N) can be declared only after response declaration.","messagePattern":"Invalid WebMock stub declaration\\. times\\(N\\) can be declared only after response declaration\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"lib/webmock/request_stub.rb","lineNumber":101,"sourceCode":"        @responses_sequences.shift if @responses_sequences.first.end?\n        @responses_sequences.first.next_response\n      else\n        @responses_sequences[0].next_response\n      end\n    end\n\n    def has_responses?\n      !@responses_sequences.empty?\n    end\n\n    def then\n      self\n    end\n\n    def times(number)\n      raise \"times(N) accepts integers >= 1 only\" if !number.is_a?(Integer) || number < 1\n      if @responses_sequences.empty?\n        raise \"Invalid WebMock stub declaration.\" +\n          \" times(N) can be declared only after response declaration.\"\n      end\n      @responses_sequences.last.times_to_repeat += number-1\n      self\n    end\n\n    def matches?(request_signature)\n      self.request_pattern.matches?(request_signature)\n    end\n\n    def to_s\n      self.request_pattern.to_s\n    end\n\n    def self.from_request_signature(signature)\n      stub = self.new(signature.method.to_sym, signature.uri.to_s)\n\n      if signature.body.to_s != ''","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/bblimke/webmock/blob/b187df8827e1f08a1684a8ddc0a5050dbd449c16/lib/webmock/request_stub.rb#L83-L119","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nstub = stub_request(:get, 'www.example.com')\nstub.times(3)\n# => RuntimeError: Invalid WebMock stub declaration...\n\n// after\nstub = stub_request(:get, 'www.example.com').to(body: 'ok')\nstub.times(3)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  stub.times(3)\nrescue RuntimeError => e\n  raise unless e.message.include?('declared only after response declaration')\n  stub.to(body: 'ok').times(3) # attach a response first, then repeat\nend","preventionTips":["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"],"tags":["webmock","ruby","dsl","stub","ordering","api-misuse"],"backgroundTag":"stub-declaration-order","analyzedSha":"b187df8827e1f08a1684a8ddc0a5050dbd449c16","analyzedAt":"2026-08-23T02:55:22.028Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}