ruby-grape/grape · error · ArgumentError
must supply type for coerce_with
Error message
must supply type for coerce_with
What it means
Grape requires every `coerce_with:` option on `requires`/`optional` to be paired with an explicit `type:`. `coerce_with` only says HOW the incoming param is converted; `type:` says WHAT the param becomes and drives later validation, defaults, and documentation. When `ParamsScope#check_coerce_with` finds a coercion method but no type, it raises ArgumentError while the API class body is being evaluated, before any request is served.
Source
Thrown at lib/grape/validations/params_scope.rb:372
# Presence runs first — `required` is forwarded to every subsequent
# validator (some short-circuit on it).
validate_presence(spec, attrs)
# Coerce runs second — later validators see the typed value.
validate_coerce(spec, attrs)
spec.validator_entries.each do |type, options|
validate(type, options, attrs, spec.required?, spec.shared_opts)
end
end
# Enforce correct usage of :coerce_with on a CoerceOptions.
# We do not allow coercion without a type, nor with +JSON+ as a type
# since that defines its own coercion method.
def check_coerce_with(coerce_options)
return unless coerce_options.coerce_method
raise ArgumentError, 'must supply type for coerce_with' unless coerce_options.type
return unless SPECIAL_JSON.include?(coerce_options.type)
raise ArgumentError, 'coerce_with disallowed for type: JSON'
end
def validate_presence(spec, attrs)
return unless spec.required?
validate('presence', spec.presence_options, attrs, true, spec.shared_opts)
end
def validate_coerce(spec, attrs)
coerce_options = spec.coerce_options
check_coerce_with(coerce_options)
# Falsy check is intentional: when a remountable API is first evaluated
# on its base instance (no configuration supplied yet),
# configuration[:some_type] evaluates to nil. Skipping instantiation
# here is correct — the real mounted instance will replay this stepView on GitHub (pinned to 22d7975629)
Solutions
- Add `type:` to the same declaration, e.g. `requires :age, type: Integer, coerce_with: ->(v) { v.to_i }`
- If the conversion belongs to a custom class, give the class a class-level `parse` method and pass it as `type:` alone (Grape custom type), dropping `coerce_with`
- If declarations are generated dynamically, assert that any hash containing `:coerce_with` also contains `:type` or `:types` before it reaches the DSL
Example fix
# before
requires :age, coerce_with: ->(v) { v.to_i }
# after
requires :age, type: Integer, coerce_with: ->(v) { v.to_i } Defensive patterns
Strategy: validation
Validate before calling
def assert_coerce_declaration!(opts)
return unless opts.key?(:coerce_with) && !opts.key?(:type) && !opts.key?(:types)
raise ArgumentError, ':coerce_with must be paired with :type (keys given: ' + opts.keys.inspect + ')'
end
assert_coerce_declaration!(type: Integer, coerce_with: ->(v) { v.to_i }) Try / catch
begin
MyAPI = Class.new(Grape::API) do
requires :age, coerce_with: ->(v) { v.to_i } # raises during class definition
end
rescue ArgumentError => e
raise "Invalid param declaration while loading MyAPI: #{e.message}"
end Prevention
- Treat `type:` and `coerce_with:` as an inseparable pair in code review
- Write one mounting spec per endpoint so declaration errors fail in CI, not at boot
- Prefer custom types with a class-level `parse` over raw `coerce_with` procs — then only `type:` is needed
When it happens
Trigger: Declaring `requires :age, coerce_with: ->(v) { v.to_i }` (proc with no type); `optional :token, coerce_with: CustomParser` (object responding to call/parse with no type); any requires/optional declaration whose options hash reaches ParamsScope with a `:coerce_with` key and no `:type`/`:types` key.
Common situations: Porting Sinatra-style endpoints and assuming the coercion proc's return value implies the type; copying example snippets that omit `type:`; building declarations from dynamically merged option hashes where the `:type` key is dropped or renamed.
Related errors
- coerce_with disallowed for type: JSON
- oneof: requires type: Hash
- oneof: must be a non-empty Array of blocks
- oneof: each variant must be a Proc
- Unknown type: #{type}
AI-assisted analysis of ruby-grape/grape@22d7975629 (2026-08-21).
Data as JSON: /api/errors/da6381b7e49dcec1.
Report an issue: GitHub.