ruby-grape/grape · error · Grape::Exceptions::MissingGroupType
group type is required
Error message
group type is required
What it means
`optional :name do ... end` opens a nested parameter group, and Grape must know the container's shape to coerce and validate it. When a block is given but no `type:` option is supplied, Grape raises Grape::Exceptions::MissingGroupType ('group type is required') at boot time. The same rule applies to `requires` with a block; only flat attributes may omit the type.
Source
Thrown at lib/grape/dsl/parameters.rb:151
return require_required_and_optional_fields(attrs.first, using:, except:) if using
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|View on GitHub (pinned to 22d7975629)
Solutions
- Add `type: Hash` for a single nested object: `optional :address, type: Hash do ... end`.
- Use `type: Array` for a list of objects, or `type: JSON` / `type: Array[JSON]` for JSON payloads.
Example fix
# before optional :address do requires :street, type: String end # raises MissingGroupType # after optional :address, type: Hash do requires :street, type: String end
Defensive patterns
Strategy: validation
Validate before calling
# Convention: every params block paired with `optional/requires ... do` MUST carry a group type # Enforce in review/lint: grep for blocks without type: # grep -nE '(optional|requires)\s+:\w+(\s*,\s*)?do' config/api - shows suspicious declarations
Prevention
- Memorize the rule: block on a param declaration means `type: Hash|Array|JSON|Array[JSON]` is mandatory.
- Extract a macro (e.g. `optional_hash :address do`) in a base class so groups always carry the type.
- Boot every endpoint in a spec (one request per route) so definition-time exceptions fail CI.
When it happens
Trigger: `optional :address do requires :street end` without a type. Copying a nested group example that relies on a default type (Grape has none). Refactoring `optional :address, type: Hash` by dropping the type while keeping the block.
Common situations: First-time use of nested params. Migrating from Grape versions or other frameworks (Rails strong params) where the container type is implicit. Renaming group parameters and accidentally removing the type option.
Related errors
- group type must be Array, Hash, JSON or Array[JSON]
- group type is required
- group type must be Array, Hash, JSON or Array[JSON]
- type #{type} should support coercion via `[]`
- #declared is not available prior to parameter validation
AI-assisted analysis of ruby-grape/grape@22d7975629 (2026-08-21).
Data as JSON: /api/errors/dfba8f4a2aa49936.
Report an issue: GitHub.