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 calledView on GitHub (pinned to 22d7975629)
Solutions
- Pass a contract class or schema: `contract MyContract` (a Dry::Validation::Contract subclass or Dry::Schema processor).
- 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
- Make contract declarations explicit: either `contract MyContract` or `contract do ... end`.
- Guard dynamic contracts: `contract(klass) if klass`.
- Mount every endpoint in a smoke spec to catch bare contract calls.
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
- Cannot inherit from contract, only schema
- must supply type for coerce_with
- coerce_with disallowed for type: JSON
- oneof: requires type: Hash
- oneof: must be a non-empty Array of blocks
AI-assisted analysis of ruby-grape/grape@22d7975629 (2026-08-21).
Data as JSON: /api/errors/d028b8b9ad2beddd.
Report an issue: GitHub.