{"record":{"id":"4e8d80c6979776ea","repo":"ruby-grape/grape","slug":"group-type-must-be-array-hash-json-or-array-json","errorCode":null,"errorMessage":"group type must be Array, Hash, JSON or Array[JSON]","messagePattern":"group type must be Array, Hash, JSON or Array\\[JSON\\]","errorType":"exception","errorClass":"Grape::Exceptions::UnsupportedGroupType","httpStatus":null,"severity":"error","filePath":"lib/grape/dsl/parameters.rb","lineNumber":152,"sourceCode":"\n        validate_attributes(attrs, **opts, &block)\n        block ? new_scope(attrs.first, type: opts[:type], as: opts[:as], &block) : push_declared_params(attrs, as: opts[:as])\n      end\n\n      # Allow, but don't require, one or more parameters for the current\n      #   endpoint.\n      # @param (see #requires)\n      # @option (see #requires)\n      def optional(*attrs, using: nil, except: nil, **opts, &block)\n        return redispatch_legacy_options(:optional, attrs, { using:, except: }.compact.merge(opts), &block) if legacy_options?(attrs)\n\n        type = opts[:type]\n        opts = @group.deep_merge(opts) if @group\n\n        # check type for optional parameter group\n        if attrs && block\n          raise Grape::Exceptions::MissingGroupType if type.nil?\n          raise Grape::Exceptions::UnsupportedGroupType unless Grape::Validations::Types.group?(type)\n        end\n\n        return require_optional_fields(attrs.first, using:, except:) if using\n\n        validate_attributes(attrs, **opts, &block)\n        block ? new_scope(attrs.first, type: opts[:type], as: opts[:as], optional: true, &block) : push_declared_params(attrs, as: opts[:as])\n      end\n\n      # Define common settings for one or more parameters\n      # @param (see #requires)\n      # @option (see #requires)\n      def with(**opts, &)\n        new_group_attrs = @group&.deep_merge(opts) || opts\n        new_group_scope(new_group_attrs, &)\n      end\n\n      %i[mutually_exclusive exactly_one_of at_least_one_of all_or_none_of].each do |validator|\n        define_method validator do |*attrs, message: nil|","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/ruby-grape/grape/blob/22d7975629846a3c0c7bd2b34e140a7a1b4af8f6/lib/grape/dsl/parameters.rb#L134-L170","documentation":"When `optional` is called with a block, the `type:` option must be a group type - one of Array, Hash, JSON, or Array[JSON] - because the block defines the members of a container. Any scalar or non-group type (String, Integer, a custom class) raises Grape::Exceptions::UnsupportedGroupType ('group type must be Array, Hash, JSON or Array[JSON]'). The check is `Grape::Validations::Types.group?(type)`.","triggerScenarios":"`optional :tags, type: String do ... end`. `optional :items, type: Integer do ... end`. Giving a group a custom class type (e.g. `type: MyCollection`) while also passing a block.","commonSituations":"Adding nested attributes to a parameter that previously held a scalar, and keeping the old type. Confusing `optional :tags, type: Array[String]` (valid, no block) with a block form. Tutorial code adapted with the wrong container type.","solutions":["Use a supported group type: `type: Hash`, `type: Array`, `type: JSON`, or `type: Array[JSON]`.","If the block was accidental (you only wanted a typed scalar), remove the block: `optional :tags, type: String`.","For arrays of scalars, use `type: Array[String]` without a block."],"exampleFix":"# before\noptional :tags, type: String do\n  requires :name, type: String\nend # raises UnsupportedGroupType\n\n# after\noptional :tags, type: Array do\n  requires :name, type: String\nend\n\n# scalar without a block\noptional :tags, type: Array[String]","handlingStrategy":"validation","validationCode":"GROUP_TYPES = [Array, Hash, JSON, Array[JSON]].freeze # JSON is Grape::JSON in params DSL\n\ndef group_type?(type) = Grape::Validations::Types.group?(type)\n\n# in a shared linter, reject params blocks whose type: is not a group type","typeGuard":"def valid_group_type?(type) = Grape::Validations::Types.group?(type)","tryCatchPattern":null,"preventionTips":["Only attach blocks to group-typed params; scalars get no block.","For member types use `type: Array[String]` etc. without a block.","Boot-time request specs catch UnsupportedGroupType before deploy."],"tags":["grape","params","group-type","optional","type-declaration"],"backgroundTag":"unsupported-group-type","analyzedSha":"22d7975629846a3c0c7bd2b34e140a7a1b4af8f6","analyzedAt":"2026-08-21T17:03:54.627Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}