{"record":{"id":"a21e6f0b48704003","repo":"ruby-grape/grape","slug":"oneof-requires-type-hash","errorCode":null,"errorMessage":"oneof: requires type: Hash","messagePattern":"oneof: requires type: Hash","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/grape/validations/params_scope.rb","lineNumber":404,"sourceCode":"        check_coerce_with(coerce_options)\n        # Falsy check is intentional: when a remountable API is first evaluated\n        # on its base instance (no configuration supplied yet),\n        # configuration[:some_type] evaluates to nil. Skipping instantiation\n        # here is correct — the real mounted instance will replay this step\n        # with the actual type value.\n        return unless coerce_options.type\n\n        validate('coerce', coerce_options, attrs, spec.required?, spec.shared_opts)\n      end\n\n      # Translate a `oneof: [proc, proc, ...]` declaration into a list of\n      # captured validator arrays — one array per variant. Each variant's\n      # block is evaluated in its own +ParamsScope+ backed by an\n      # {OneofCollector} so the full params DSL is available inside variants\n      # and the resulting validators are kept out of the real API's\n      # registration list.\n      def process_oneof!(validations)\n        raise ArgumentError, 'oneof: requires type: Hash' unless validations[:type] == Hash\n\n        variants = validations[:oneof]\n        raise ArgumentError, 'oneof: must be a non-empty Array of blocks' unless variants.is_a?(Array) && variants.any?\n        raise ArgumentError, 'oneof: each variant must be a Proc' unless variants.all?(Proc)\n\n        validations[:oneof] = variants.map { |block| OneofCollector.collect(block) }\n      end\n\n      def validate(type, options, attrs, required, opts)\n        validator_class = Validations.require_validator(type)\n        validator_instance = validator_class.new(\n          attrs,\n          options,\n          required,\n          self,\n          opts\n        )\n        @api.inheritable_setting.add_validation(validator_instance)","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/ruby-grape/grape/blob/22d7975629846a3c0c7bd2b34e140a7a1b4af8f6/lib/grape/validations/params_scope.rb#L386-L422","documentation":"`oneof:` declares alternative shapes for a parameter: each variant is a block evaluated in its own ParamsScope backed by a OneofCollector, so the full params DSL (requires, optional, nesting) is available inside. Because every variant describes nested keys, the parent declaration must be exactly `type: Hash`; `process_oneof!` raises ArgumentError at definition time otherwise.","triggerScenarios":"`requires :filter, oneof: [-> { requires :name }, -> { requires :id }]` with no `type:`; `optional :q, type: Array, oneof: [...]` (any type other than exactly the `Hash` constant, including `Array[Hash]`).","commonSituations":"Adopting the oneof syntax from changelogs or examples without noticing the mandatory type pairing; converting a scalar `types: [Integer, String]` union into a structural oneof and leaving the old type in place.","solutions":["Add `type: Hash` to the same declaration: `requires :filter, type: Hash, oneof: [-> { ... }, -> { ... }]`","Use exactly the `Hash` constant — custom hash-like classes fail the equality check","If the alternatives are scalar types rather than nested keys, use `types: [A, B]` instead of `oneof:`"],"exampleFix":"# before\nrequires :filter, oneof: [-> { requires :name }, -> { requires :id }]\n\n# after\nrequires :filter, type: Hash, oneof: [\n  -> { requires :name, type: String },\n  -> { requires :id, type: Integer }\n]","handlingStrategy":"validation","validationCode":"def assert_oneof_shape!(opts)\n  return unless opts.key?(:oneof) && opts[:type] != Hash\n\n  raise ArgumentError, 'oneof: declarations must pair with type: Hash'\nend","typeGuard":null,"tryCatchPattern":"begin\n  requires :filter, oneof: [-> { requires :name }]\nrescue ArgumentError => e\n  raise \"oneof declaration error: #{e.message}\"\nend","preventionTips":["Memorize the oneof shape: `type: Hash, oneof: [proc, proc]` — always four parts","Use `types:` for scalar unions; reserve `oneof:` for structural alternatives","Cover every oneof declaration with a mounting spec that exercises each variant"],"tags":["grape","params","oneof","validation","argumenterror","dsl"],"backgroundTag":"oneof-validation-misconfigured","analyzedSha":"22d7975629846a3c0c7bd2b34e140a7a1b4af8f6","analyzedAt":"2026-08-21T17:03:54.627Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}