ruby-grape/grape · warning
Passing a positional options Hash to `#{method_name}` is dep
Error message
Passing a positional options Hash to `#{method_name}` is deprecated. Pass keyword arguments instead. What it means
The parameter DSL (`requires`, `optional`, etc.) now takes keyword options. A trailing positional Hash (`requires :id, { type: Integer }`) used to be peeled off by `extract_options!`; under Ruby 3 it lands in the splat and would silently be treated as another parameter name. Grape detects the shape, warns via `Grape.deprecator`, and re-invokes the method with the Hash converted to keywords.
Source
Thrown at lib/grape/dsl/parameters.rb:231
params = map_params(params, @element) if @element
params
end
private
# @deprecated A trailing positional options Hash is deprecated; pass keyword
# arguments instead. Before Ruby 3 keyword separation this Hash was pulled
# off the argument list by `extract_options!`; now it lands in the splat and
# would silently be treated as a parameter name.
def legacy_options?(args)
args.size > 1 && args.last.is_a?(Hash)
end
# Re-invokes +method_name+ with the trailing Hash splatted as keyword
# arguments, so Ruby routes its keys to the same place they would have
# reached had the caller omitted the braces.
def redispatch_legacy_options(method_name, args, opts, &)
Grape.deprecator.warn("Passing a positional options Hash to `#{method_name}` is deprecated. Pass keyword arguments instead.")
__send__(method_name, *args[0..-2], **args.last.merge(opts), &)
end
def first_hash_key_or_param(parameter)
parameter.is_a?(Hash) ? parameter.keys.first : parameter
end
def map_params(params, element, is_array: false)
case params
when Array
params.map do |el|
map_params(el, element, is_array: true)
end
when Hash
params[element] || (@optional && is_array ? EmptyOptionalValue : {})
when EmptyOptionalValue
EmptyOptionalValue
elseView on GitHub (pinned to 22d7975629)
Solutions
- Pass keywords without braces: `requires :id, type: Integer, desc: 'user id'`
- In macros, double-splat the options: `requires name, **opts`
- Run CI with `Grape.deprecator.behavior = :raise` to catch remaining positional-hash call sites
Example fix
# before
requires :id, { type: Integer, desc: 'user id' }
# after
requires :id, type: Integer, desc: 'user id' Defensive patterns
Strategy: validation
Validate before calling
# CI guard: deprecations raise in the test env, catching positional option hashes Grape.deprecator.behavior = :raise if Rails.env.test?
Prevention
- Always pass parameter options as keywords: `requires :id, type: Integer`
- In macros, double-splat: `requires name, **opts`
- During upgrades, grep for `requires :x, {` and `optional :x, {` patterns
When it happens
Trigger: `requires :id, { type: Integer, desc: 'user id' }`; `optional :page, { default: 1 }`; any parameter DSL call whose last positional argument is a Hash.
Common situations: Pre-Ruby-3 codebases; ERB templates or generators emitting hash literals into DSL calls; shared macros that splat an options hash positionally into `requires`.
Related errors
- Passing a positional options Hash to `desc` is deprecated. P
- Passing a positional options Hash to `#{method_name}` is dep
- Either contract or block must be provided
- must supply type for coerce_with
- coerce_with disallowed for type: JSON
AI-assisted analysis of ruby-grape/grape@22d7975629 (2026-08-21).
Data as JSON: /api/errors/41261a541ddef04a.
Report an issue: GitHub.