bblimke/webmock · error · ArgumentError
#to_return_json does not support passing a block
Error message
#to_return_json does not support passing a block
What it means
RequestStub#to_return_json builds JSON responses from one or more response hashes: it flattens the arguments, serializes bodies, and sets the JSON content type. Unlike to_return, it accepts no block - to_return_json(*response_hashes) raises ArgumentError immediately when a block is attached (lib/webmock/request_stub.rb:30). Dynamic JSON responses are still supported: a lambda passed as the :body value is called with the request signature and its return value is serialized to JSON.
Source
Thrown at lib/webmock/request_stub.rb:30
end
def with(params = {}, &block)
@request_pattern.with(params, &block)
self
end
def to_return(*response_hashes, &block)
if block
@responses_sequences << ResponsesSequence.new([ResponseFactory.response_for(block)])
else
@responses_sequences << ResponsesSequence.new([*response_hashes].flatten.map {|r| ResponseFactory.response_for(r)})
end
self
end
alias_method :and_return, :to_return
def to_return_json(*response_hashes)
raise ArgumentError, '#to_return_json does not support passing a block' if block_given?
json_response_hashes = [*response_hashes].flatten.map do |resp_h|
headers, body = resp_h.values_at(:headers, :body)
json_body = if body.respond_to?(:call)
->(request_signature) {
b = if body.respond_to?(:arity) && body.arity == 1
body.call(request_signature)
else
body.call
end
b = b.to_json unless b.is_a?(String)
b
}
elsif !body.is_a?(String)
body.to_json
else
bodyView on GitHub (pinned to b187df8827)
Solutions
- Remove the block and put the payload in the hash: .to_return_json(status: 200, body: { id: 1 })
- For dynamic JSON, pass a lambda as the :body value: .to_return_json(status: 200, body: ->(request) { { id: request.body[/\d+/].to_i } })
- If status and headers must also vary per request, use the classic form: .to_return(lambda { |request_signature| { status: 200, body: { id: 1 }.to_json } })
Example fix
# before
stub.to_return_json(status: 200) { |request| { id: request.body[/\d+/].to_i } } # ArgumentError
# after
stub.to_return_json(status: 200, body: ->(request) { { id: request.body[/\d+/].to_i } }) Defensive patterns
Strategy: validation
Validate before calling
# Helper that routes dynamic JSON through :body instead of a block: def stub_json(stub, dynamic: nil, **opts) dynamic ? stub.to_return_json(body: dynamic, **opts) : stub.to_return_json(**opts) end
Prevention
- Do not forward &block to to_return_json in helper methods
- Use a body: lambda for dynamic JSON responses
- Enable Lint/UnusedBlockArgument so forgotten blocks surface
When it happens
Trigger: .to_return_json(status: 200) { ... } - a block, typically left over from copy-pasting a to_return { |request| ... } dynamic stub. Using the and_return_json alias with a block. A spec helper that captures and blindly forwards &block to to_return_json.
Common situations: Migrating string-body dynamic stubs to to_return_json and keeping the block; helper methods that always forward a block parameter; examples written against a different stubbing API.
Related errors
- must be one of: #{valid_types}, but you've used a #{@body.cl
- must be one of: #{valid_types}. '#{@body.class}' given.
- Wrong order. Use :before_local_stubs or :after_local_stubs
- Invalid JSON string: #{yaml}, Error: #{e.inspect}
- Invalid WebMock stub declaration. times(N) can be declared o
AI-assisted analysis of bblimke/webmock@b187df8827 (2026-08-23).
Data as JSON: /api/errors/aaba33116a66916e.
Report an issue: GitHub.