lostisland/faraday · error · ArgumentError
unknown http method: #{method}
Error message
unknown http method: #{method} What it means
Connection#run_request validates the HTTP method against Connection::METHODS, a frozen Set of exactly :get, :post, :put, :delete, :head, :patch, :options and :trace. Anything else — strings, upcase or mixed-case symbols, or non-standard verbs — raises ArgumentError before the request is built. This is a deliberate whitelist: Faraday only executes well-known methods, unlike Net::HTTP which accepts arbitrary verbs.
Source
Thrown at lib/faraday/connection.rb:441
else
query_values.to_query(options.params_encoder)
end
uri
end
# Builds and runs the Faraday::Request.
#
# @param method [Symbol] HTTP method.
# @param url [String, URI, nil] String or URI to access.
# @param body [String, Hash, Array, nil] The request body that will eventually be converted to
# a string; middlewares can be used to support more complex types.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# @return [Faraday::Response]
def run_request(method, url, body, headers)
unless METHODS.include?(method)
raise ArgumentError, "unknown http method: #{method}"
end
request = build_request(method) do |req|
req.options.proxy = proxy_for_request(url)
req.url(url) if url
req.headers.update(headers) if headers
req.body = body if body
yield(req) if block_given?
end
builder.build_response(self, request)
end
# Creates and configures the request object.
#
# @param method [Symbol]
#
# @yield [Faraday::Request] if block givenView on GitHub (pinned to b25b1b26cc)
Solutions
- Normalize the method before calling run_request: method = method.to_s.downcase.strip.to_sym so 'GET', :Get and 'get ' all become :get.
- Whitelist-check the method against your own allow-list and fail with your own error message: Faraday::Connection::METHODS.include?(method).
- For genuinely non-standard verbs that the wire protocol still requires, build the request without run_request's validation: req = conn.build_request(:purge) { |r| r.url('/x') }; conn.builder.build_response(conn, req) — build_request performs no METHODS check.
- As a last resort, extend the whitelist at boot: Faraday::Connection::METHODS << :purge (METHODS is a mutable Set), then conn.run_request(:purge, ...) passes — document this loudly because built-in adapters may still reject the verb.
Example fix
# before
method = params[:method] # e.g. "PURGE" from config
conn.run_request(method, '/items', nil, nil)
# => ArgumentError: unknown http method: PURGE
# after
method = params[:method].downcase.to_sym
unless Faraday::Connection::METHODS.include?(method)
raise ArgumentError, "unsupported method #{method}"
end
conn.run_request(method, '/items', nil, nil) Defensive patterns
Strategy: validation
Validate before calling
method = method.to_s.downcase.to_sym
raise ArgumentError, "unsupported method #{method}" unless Faraday::Connection::METHODS.include?(method)
conn.run_request(method, url, body, headers) Type guard
def supported_http_method?(method) Faraday::Connection::METHODS.include?(method.to_s.downcase.to_sym) end
Try / catch
begin
conn.run_request(method, url, body, headers)
rescue ArgumentError => e
raise unless e.message.start_with?('unknown http method')
# normalize casing/strings and retry once
conn.run_request(method.to_s.downcase.to_sym, url, body, headers)
end Prevention
- Whitelist methods at your API boundary instead of forwarding raw user input to run_request.
- Store HTTP methods in config as lowercase symbols (:post, not 'POST') and normalize defensively with to_s.downcase.to_sym.
- For custom verbs, prefer build_request + builder.build_response which bypass the METHODS check, over monkey-patching the whitelist.
When it happens
Trigger: Calling conn.run_request('get', ...) with a String instead of the lowercase Symbol :get; passing :GET or :Get from a copied curl example; data-driven code that reads the method from JSON/YAML config and forwards it unnormalized; requesting CDN or WebDAV verbs such as :purge, :propfind, :mkcol or :copy which are not in the whitelist.
Common situations: Purging Fastly/Akamai caches (the :purge verb is the classic case); WebDAV or CalDAV clients; porting Net::HTTP code where arbitrary methods work; config files storing 'POST' as a string; user input choosing the method in an API gateway scenario.
Related errors
- Expected :read, :write, :open. Got #{type.inspect} :(
- #memoized must be called with a block
- Unexpected params received (got #{params.size} instead of 1)
- bad argument (expected URI object or URI string)
- no stubbed request for #{env[:method]} #{env[:url]} #{env[:b
AI-assisted analysis of lostisland/faraday@b25b1b26cc (2026-08-21).
Data as JSON: /api/errors/64e360827dc745b4.
Report an issue: GitHub.