ruby-grape/grape · error · ArgumentError

Either contract or block must be provided

Error message

Either contract or block must be provided

What it means

The `contract` DSL declares parameter validation via dry-validation: either pass an existing contract/schema or provide an inline block that defines a Dry::Schema::Params schema. Calling `contract` with neither - `contract` bare - gives Grape nothing to build a validator from, so it raises ArgumentError ('Either contract or block must be provided') at definition time.

Source

Thrown at lib/grape/dsl/validations.rb:20

module Grape
  module DSL
    module Validations
      # Opens a root-level ParamsScope, defining parameter coercions and
      # validations for the endpoint.
      # @yield instance context of the new scope
      def params(&)
        Grape::Validations::ParamsScope.new(api: self, type: Hash, &)
      end

      # Declare the contract to be used for the endpoint's parameters.
      # @param contract [Class<Dry::Validation::Contract> | Dry::Schema::Processor]
      #   The contract or schema to be used for validation. Optional.
      # @yield a block yielding a new instance of Dry::Schema::Params
      #   subclass, allowing to define the schema inline. When the
      #   +contract+ parameter is a schema, it will be used as a parent. Optional.
      def contract(contract = nil, &block)
        raise ArgumentError, 'Either contract or block must be provided' unless contract || block
        raise ArgumentError, 'Cannot inherit from contract, only schema' if block && contract.respond_to?(:schema)

        Grape::Validations::ContractScope.new(self, contract, &block)
      end

      private

      # Clears all defined parameters and validations. The main purpose of it is to clean up
      # settings, so next endpoint won't interfere with previous one.
      #
      #    params do
      #      # params for the endpoint below this block
      #    end
      #    post '/current' do
      #      # whatever
      #    end
      #
      #    # somewhere between them the reset_validations! method gets called

View on GitHub (pinned to 22d7975629)

Solutions

  1. Pass a contract class or schema: `contract MyContract` (a Dry::Validation::Contract subclass or Dry::Schema processor).
  2. Or define the schema inline: `contract do required(:name).filled(:string) end`.

Example fix

# before
get '/ping' do
  contract # raises
  ...
end

# after
contract do
  required(:name).filled(:string)
end

# or
contract Users::CreateContract
Defensive patterns

Strategy: validation

Validate before calling

raise ArgumentError, 'contract needs a class or a block' unless contract_class || contract_block

Prevention

When it happens

Trigger: `contract` on its own line inside an endpoint or API class. `contract nil` from a variable that failed to load. Refactoring a contract block into a class but leaving the bare call behind.

Common situations: Migrating from `params do ... end` to dry-validation contracts. Feature-flag code paths that sometimes pass no contract. Copying a contract example incompletely.

Related errors


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