bblimke/webmock · error · ArgumentError

Wrong order. Use :before_local_stubs or :after_local_stubs

Error message

Wrong order. Use :before_local_stubs or :after_local_stubs

What it means

WebMock.globally_stub_request(order = :before_local_stubs, &block) registers a global stub consulted on every request; StubRegistry#register_global_stub accepts only the symbols :before_local_stubs and :after_local_stubs (lib/webmock/stub_registry.rb:24), which decide whether the global stub wins over, or yields to, test-local stub_request stubs. Any other value - :before, :after, a string like 'before_local_stubs', or a typo - raises ArgumentError, because %i[before_local_stubs after_local_stubs].include?(order) compares symbols strictly and never matches strings.

Source

Thrown at lib/webmock/stub_registry.rb:24

    include Singleton

    attr_accessor :request_stubs

    def initialize
      reset!
    end

    def global_stubs
      @global_stubs ||= Hash.new { |h, k| h[k] = [] }
    end

    def reset!
      self.request_stubs = []
    end

    def register_global_stub(order = :before_local_stubs, &block)
      unless %i[before_local_stubs after_local_stubs].include?(order)
        raise ArgumentError.new("Wrong order. Use :before_local_stubs or :after_local_stubs")
      end

      # This hash contains the responses returned by the block,
      # keyed by the exact request (using the object_id).
      # That way, there's no race condition in case #to_return
      # doesn't run immediately after stub.with.
      responses = {}
      response_lock = Mutex.new

      stub = ::WebMock::RequestStub.new(:any, ->(uri) { true }).with { |request|
        update_response = -> { responses[request.object_id] = yield(request) }

        # The block can recurse, so only lock if we don't already own it
        if response_lock.owned?
          update_response.call
        else
          response_lock.synchronize(&update_response)
        end

View on GitHub (pinned to b187df8827)

Solutions

  1. Use the exact symbols: WebMock.globally_stub_request(:before_local_stubs) { |request_signature| ... } or :after_local_stubs
  2. If precedence does not matter, omit the argument - :before_local_stubs is the default
  3. If the order value comes from config, normalize it first: order.to_s.to_sym validated against the two allowed symbols

Example fix

# before
WebMock.globally_stub_request('before') { |req| ... }  # ArgumentError: Wrong order

# after
WebMock.globally_stub_request(:before_local_stubs) { |req| ... }
Defensive patterns

Strategy: validation

Validate before calling

STUB_ORDER = %i[before_local_stubs after_local_stubs].freeze
order = STUB_ORDER.include?(order) ? order : :before_local_stubs
WebMock.globally_stub_request(order, &block)

Type guard

def valid_stub_order?(o)
  %i[before_local_stubs after_local_stubs].include?(o)
end

Try / catch

begin
  WebMock.globally_stub_request(order, &block)
rescue ArgumentError
  WebMock.globally_stub_request(:before_local_stubs, &block)
end

Prevention

When it happens

Trigger: WebMock.globally_stub_request(:before) { |req| ... } copied from an old blog post or outdated team docs. Passing 'after_local_stubs' as a String - the symbol-array include? fails on strings. An order value read from YAML/ENV where symbols became strings or were misspelled.

Common situations: Global stubs for third-party APIs set up in rails_helper/spec_helper; documentation written against an older webmock API; config-driven spec setup that passes through untyped strings.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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