lostisland/faraday · error · ArgumentError
Expected :read, :write, :open. Got #{type.inspect} :(
Error message
Expected :read, :write, :open. Got #{type.inspect} :( What it means
Faraday::Adapter#request_timeout resolves which timeout option to use by looking the type up in the frozen TIMEOUT_KEYS map ({ read: :read_timeout, open: :open_timeout, write: :write_timeout }), falling back to the generic :timeout option. The map only accepts the symbols :read, :write and :open; any other value raises ArgumentError. It is mostly an adapter-author-facing API: built-in adapters call it with hardcoded symbols, so end users usually hit it from custom adapters or direct calls.
Source
Thrown at lib/faraday/adapter.rb:95
env.response.finish(env) unless env.parallel? || !finished
env.response
end
# Fetches either a read, write, or open timeout setting. Defaults to the
# :timeout value if a more specific one is not given.
#
# @param type [Symbol] Describes which timeout setting to get: :read,
# :write, or :open.
# @param options [Hash] Hash containing Symbol keys like :timeout,
# :read_timeout, :write_timeout, or :open_timeout
#
# @return [Integer, nil] Timeout duration in seconds, or nil if no timeout
# has been set.
def request_timeout(type, options)
key = TIMEOUT_KEYS.fetch(type) do
msg = "Expected :read, :write, :open. Got #{type.inspect} :("
raise ArgumentError, msg
end
options[key] || options[:timeout]
end
end
end
require 'faraday/adapter/test'
View on GitHub (pinned to b25b1b26cc)
Solutions
- Pass one of the three supported symbols: :read, :write, or :open (request_timeout(:open, env[:request]) maps to options[:open_timeout] || options[:timeout]).
- If the type comes from configuration, normalize it before the call: type = type.to_s.downcase.to_sym and reject values outside the set.
- For timeout kinds with no Faraday mapping (e.g. a TLS handshake timeout), read the option directly from the options hash (options[:ssl_timeout]) instead of going through request_timeout.
- In custom adapter specs, enumerate the supported types so a renamed symbol fails in CI instead of in production.
Example fix
// before (custom adapter) def call(env) timeout = request_timeout(:connect, env[:request]) # => ArgumentError: Expected :read, :write, :open. Got :connect :( end // after def call(env) timeout = request_timeout(:open, env[:request]) # maps to :open_timeout / :timeout end
Defensive patterns
Strategy: validation
Validate before calling
return unless Faraday::Adapter::TIMEOUT_KEYS.key?(type) timeout = adapter.request_timeout(type, options)
Type guard
def valid_timeout_type?(type) Faraday::Adapter::TIMEOUT_KEYS.key?(type) end
Try / catch
begin
adapter.request_timeout(type, options)
rescue ArgumentError => e
logger.warn("unsupported timeout type #{type}: #{e.message}")
options[:timeout] # fall back to the generic timeout
end Prevention
- Use only the symbols :read, :write, :open; they map to :read_timeout/:write_timeout/:open_timeout with :timeout as fallback.
- When the type comes from config or user input, whitelist-normalize it: type.to_s.downcase.to_sym then check membership before calling.
- In custom adapters, unit-test the timeout branch with all three symbols so renames break CI, not production.
When it happens
Trigger: Calling request_timeout with an unsupported symbol, e.g. request_timeout(:connect, options), request_timeout(:total, ...) or a string like 'read' instead of :read. Writing a custom adapter that copies timeout handling from another HTTP library and reuses its option names (:connect_timeout, :ssl_timeout). A typo such as :wirte or :opne.
Common situations: Authoring or maintaining a custom Faraday adapter (the main real-world source); refactoring timeout code and renaming the type symbols; passing a user-supplied configuration string straight through as the type argument instead of normalizing it to a symbol.
Related errors
- unknown http method: #{method}
- #memoized must be called with a block
- An attempt to run a request with a Faraday::Connection witho
- Unexpected params received (got #{params.size} instead of 1)
- bad argument (expected URI object or URI string)
AI-assisted analysis of lostisland/faraday@b25b1b26cc (2026-08-21).
Data as JSON: /api/errors/1bf1bdbf163d7281.
Report an issue: GitHub.