lostisland/faraday · error · Faraday::Adapter::Test::Stubs::NotFound

no stubbed request for #{env[:method]} #{env[:url]} #{env[:b

Error message

no stubbed request for #{env[:method]} #{env[:url]} #{env[:body]} #{env[:headers]}

What it means

Faraday's test adapter replaces real HTTP with stubs registered on a Faraday::Adapter::Test::Stubs object. On every request the adapter calls stubs.match(env); when no registered stub matches the request (method, host, path, query, and under strict_mode also headers and body), it raises Stubs::NotFound. The message deliberately echoes the exact method, URL, body and headers of the unmatched request so you can diff it against your stub declarations.

Source

Thrown at lib/faraday/adapter/test.rb:285

        super(app)
        @stubs = stubs || Stubs.new
        configure(&block) if block
      end

      def configure
        yield(stubs)
      end

      # @param env [Faraday::Env]
      def call(env)
        super

        env.request.params_encoder ||= Faraday::Utils.default_params_encoder
        env[:params] = env.params_encoder.decode(env[:url].query) || {}
        stub, meta = stubs.match(env)

        unless stub
          raise Stubs::NotFound, "no stubbed request for #{env[:method]} " \
                                 "#{env[:url]} #{env[:body]} #{env[:headers]}"
        end

        block_arity = stub.block.arity
        params = if block_arity >= 0
                   [env, meta].take(block_arity)
                 else
                   [env, meta]
                 end

        timeout = request_timeout(:open, env[:request])
        timeout ||= request_timeout(:read, env[:request])

        status, headers, body =
          if timeout
            ::Timeout.timeout(timeout, Faraday::TimeoutError) do
              stub.block.call(*params)
            end

View on GitHub (pinned to b25b1b26cc)

Solutions

  1. Read the error message: it prints the actual method, URL, body and headers of the request that failed to match, and compare them field-by-field with your stub declaration.
  2. Add or correct the stub for that exact request: stubs.get('https://api.example.com/api/users/1') { ... } — remember the stub path must include the host when the connection requests an absolute URL.
  3. If only headers or body differ, disable strict matching: stubs.strict_mode = false (the default) so stubs match on method/path/query only.
  4. Stub the auxiliary request your middleware makes (e.g. the token endpoint), or disable that middleware in the test setup.
  5. Call stubs.verify_stubbed_calls at the end of tests to also catch stubs that were never hit, keeping expectations two-way.

Example fix

# before
stubs = Faraday::Adapter::Test::Stubs.new
stubs.get('/api/users') { [200, {}, '[]'] }
conn = Faraday.new('https://api.example.com') do |b|
  b.adapter :test, stubs
end
conn.get('/api/users/1') # => Stubs::NotFound

# after
stubs.get('/api/users/1') { [200, {}, '[{"id":1}]'] }
conn.get('/api/users/1') # => 200
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

begin
  conn.get('/api/users/1')
rescue Faraday::Adapter::Test::Stubs::NotFound => e
  # e.message contains the unmatched method, URL, body and headers
  flunk "unstubbed request — stub it or fix the path: #{e.message}"
end

Prevention

When it happens

Trigger: Declaring stubs.get('/api/users') but requesting '/api/users/1'; stubbing a path on a different host than the connection's url_prefix; enabling stubs.strict_mode = true so a default User-Agent or Content-Type header no longer matches; a middleware (retry, token refresh, redirect follow) issuing an extra HTTP call you never stubbed; requesting a verb (:post) when only :get was stubbed; query params differing (?page=2 vs stubbed ?page=1).

Common situations: RSpec/Minitest suites using b.adapter :test, stubs; app code changes a path or adds a query param but the test stubs are not updated; strict_mode enabled to catch sloppy stubs which then flags harmless header differences; OAuth client middleware fetching a token in the background during a stubbed request; parallel test runs sharing stubs non-atomically.

Related errors


AI-assisted analysis of lostisland/faraday@b25b1b26cc (2026-08-21). Data as JSON: /api/errors/9ac1af68dca54fc1. Report an issue: GitHub.