{"record":{"id":"d028b8b9ad2beddd","repo":"ruby-grape/grape","slug":"either-contract-or-block-must-be-provided","errorCode":null,"errorMessage":"Either contract or block must be provided","messagePattern":"Either contract or block must be provided","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/grape/dsl/validations.rb","lineNumber":20,"sourceCode":"\nmodule Grape\n  module DSL\n    module Validations\n      # Opens a root-level ParamsScope, defining parameter coercions and\n      # validations for the endpoint.\n      # @yield instance context of the new scope\n      def params(&)\n        Grape::Validations::ParamsScope.new(api: self, type: Hash, &)\n      end\n\n      # Declare the contract to be used for the endpoint's parameters.\n      # @param contract [Class<Dry::Validation::Contract> | Dry::Schema::Processor]\n      #   The contract or schema to be used for validation. Optional.\n      # @yield a block yielding a new instance of Dry::Schema::Params\n      #   subclass, allowing to define the schema inline. When the\n      #   +contract+ parameter is a schema, it will be used as a parent. Optional.\n      def contract(contract = nil, &block)\n        raise ArgumentError, 'Either contract or block must be provided' unless contract || block\n        raise ArgumentError, 'Cannot inherit from contract, only schema' if block && contract.respond_to?(:schema)\n\n        Grape::Validations::ContractScope.new(self, contract, &block)\n      end\n\n      private\n\n      # Clears all defined parameters and validations. The main purpose of it is to clean up\n      # settings, so next endpoint won't interfere with previous one.\n      #\n      #    params do\n      #      # params for the endpoint below this block\n      #    end\n      #    post '/current' do\n      #      # whatever\n      #    end\n      #\n      #    # somewhere between them the reset_validations! method gets called","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/ruby-grape/grape/blob/22d7975629846a3c0c7bd2b34e140a7a1b4af8f6/lib/grape/dsl/validations.rb#L2-L38","documentation":"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.","triggerScenarios":"`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.","commonSituations":"Migrating from `params do ... end` to dry-validation contracts. Feature-flag code paths that sometimes pass no contract. Copying a contract example incompletely.","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`."],"exampleFix":"# before\nget '/ping' do\n  contract # raises\n  ...\nend\n\n# after\ncontract do\n  required(:name).filled(:string)\nend\n\n# or\ncontract Users::CreateContract","handlingStrategy":"validation","validationCode":"raise ArgumentError, 'contract needs a class or a block' unless contract_class || contract_block","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["grape","contract","dry-validation","params","dsl"],"backgroundTag":"missing-contract-definition","analyzedSha":"22d7975629846a3c0c7bd2b34e140a7a1b4af8f6","analyzedAt":"2026-08-21T17:03:54.627Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}