ruby-grape/grape · error · Grape::Exceptions::UnsupportedGroupType

group type must be Array, Hash, JSON or Array[JSON]

Error message

group type must be Array, Hash, JSON or Array[JSON]

What it means

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)`.

Source

Thrown at lib/grape/dsl/parameters.rb:152

        validate_attributes(attrs, **opts, &block)
        block ? new_scope(attrs.first, type: opts[:type], as: opts[:as], &block) : push_declared_params(attrs, as: opts[:as])
      end

      # Allow, but don't require, one or more parameters for the current
      #   endpoint.
      # @param (see #requires)
      # @option (see #requires)
      def optional(*attrs, using: nil, except: nil, **opts, &block)
        return redispatch_legacy_options(:optional, attrs, { using:, except: }.compact.merge(opts), &block) if legacy_options?(attrs)

        type = opts[:type]
        opts = @group.deep_merge(opts) if @group

        # check type for optional parameter group
        if attrs && block
          raise Grape::Exceptions::MissingGroupType if type.nil?
          raise Grape::Exceptions::UnsupportedGroupType unless Grape::Validations::Types.group?(type)
        end

        return require_optional_fields(attrs.first, using:, except:) if using

        validate_attributes(attrs, **opts, &block)
        block ? new_scope(attrs.first, type: opts[:type], as: opts[:as], optional: true, &block) : push_declared_params(attrs, as: opts[:as])
      end

      # Define common settings for one or more parameters
      # @param (see #requires)
      # @option (see #requires)
      def with(**opts, &)
        new_group_attrs = @group&.deep_merge(opts) || opts
        new_group_scope(new_group_attrs, &)
      end

      %i[mutually_exclusive exactly_one_of at_least_one_of all_or_none_of].each do |validator|
        define_method validator do |*attrs, message: nil|

View on GitHub (pinned to 22d7975629)

Solutions

  1. Use a supported group type: `type: Hash`, `type: Array`, `type: JSON`, or `type: Array[JSON]`.
  2. If the block was accidental (you only wanted a typed scalar), remove the block: `optional :tags, type: String`.
  3. For arrays of scalars, use `type: Array[String]` without a block.

Example fix

# before
optional :tags, type: String do
  requires :name, type: String
end # raises UnsupportedGroupType

# after
optional :tags, type: Array do
  requires :name, type: String
end

# scalar without a block
optional :tags, type: Array[String]
Defensive patterns

Strategy: validation

Validate before calling

GROUP_TYPES = [Array, Hash, JSON, Array[JSON]].freeze # JSON is Grape::JSON in params DSL

def group_type?(type) = Grape::Validations::Types.group?(type)

# in a shared linter, reject params blocks whose type: is not a group type

Type guard

def valid_group_type?(type) = Grape::Validations::Types.group?(type)

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Related errors


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