ruby-grape/grape · warning

Passing a positional options Hash to `desc` is deprecated. P

Error message

Passing a positional options Hash to `desc` is deprecated. Pass keyword arguments instead.

What it means

`desc` now takes keyword arguments. Under Ruby 3 keyword separation, a Hash passed positionally (`desc 'text', { success: Entity }`) no longer lands in the options slot — Grape detects it in the splat, warns through `Grape.deprecator`, and merges it with the keyword options for backwards compatibility. The positional form will be removed in a future release.

Source

Thrown at lib/grape/dsl/desc.rb:55

      # @example
      #
      #     desc 'create a user'
      #     post '/users' do
      #       # ...
      #     end
      #
      #     desc 'find a user' do
      #       detail 'locates the user from the given user ID'
      #       failure [ [404, 'Couldn\'t find the given user' ] ]
      #       success User::Entity
      #     end
      #     get '/user/:id' do
      #       # ...
      #     end
      #
      def desc(description, *legacy_options, **options, &config_block)
        if legacy_options.any?
          Grape.deprecator.warn('Passing a positional options Hash to `desc` is deprecated. Pass keyword arguments instead.')
          options = legacy_options.first.merge(options)
        end

        settings =
          if config_block
            endpoint_config = defined?(configuration) ? configuration : nil
            Grape::Util::ApiDescription.new(description, endpoint_config, &config_block).settings
          else
            options.merge(description:)
          end
        # Only the route scope is consumed downstream (by +route+ and the
        # route's readers, e.g. +http_codes+); the namespace scope was
        # write-only, so it is no longer populated.
        inheritable_setting.route_description = settings
      end
    end
  end
end

View on GitHub (pinned to 22d7975629)

Solutions

  1. Drop the braces and pass keywords: `desc 'find a user', summary: 'x', success: User::Entity`
  2. Or use the block form: `desc 'find a user' do ... end`
  3. Set `Grape.deprecator.behavior = :raise` in the test environment to flush out every remaining call site

Example fix

# before
desc 'find a user', { success: User::Entity, failure: [[404, 'Not Found']] }

# after
desc 'find a user', success: User::Entity, failure: [[404, 'Not Found']]
Defensive patterns

Strategy: validation

Validate before calling

# CI guard: turn deprecations into failures so positional-hash `desc` calls cannot slip through
Grape.deprecator.behavior = :raise if ENV['CI']

Prevention

When it happens

Trigger: `desc 'find a user', { summary: 'x', success: User::Entity }` (explicit braces); `desc('find a user', { failure: [[404, 'Not Found']] })`; any `desc` call whose second positional argument is a Hash.

Common situations: Apps written before the Ruby 3 keyword split; upgrading Grape across a major version that keyword-ified the DSL; code generators that emit hash literals into `desc` calls.

Related errors


AI-assisted analysis of ruby-grape/grape@22d7975629 (2026-08-21). Data as JSON: /api/errors/936a1e8a97c41e06. Report an issue: GitHub.