ruby-grape/grape · error · ArgumentError

Representation of type #{representation.class} cannot be mer

Error message

Representation of type #{representation.class} cannot be merged.

What it means

When `present` is called while a response body already exists and an entity class is involved, Grape merges the new representation into the existing body with `merge`. Entities representing a collection produce an Array (or another non-Hash) value, which does not respond to `merge`, so Grape raises 'Representation of type Array cannot be merged.' instead of silently producing a broken body.

Source

Thrown at lib/grape/dsl/entity.rb:37

      # @param options [Hash] additional options forwarded to the entity's `represent` call.
      #
      # @example
      #
      #   get '/users/:id' do
      #     present User.find(params[:id]),
      #       with: API::Entities::User,
      #       admin: current_user.admin?
      #   end
      def present(*args, root: nil, with: nil, **options)
        key, object = args.count == 2 && args.first.is_a?(Symbol) ? args : [nil, args.first]
        entity_class = with || entity_class_for_obj(object)
        representation = entity_class ? entity_representation_for(entity_class, object, options) : object
        representation = { root => representation } if root

        if key
          representation = body&.merge(key => representation) || { key => representation }
        elsif entity_class.present? && body
          raise ArgumentError, "Representation of type #{representation.class} cannot be merged." unless representation.respond_to?(:merge)

          representation = body.merge(representation)
        end

        body representation
      end

      # Attempt to locate the Entity class for a given object, if not given
      # explicitly. This is done by looking for the presence of Klass::Entity,
      # where Klass is the class of the `object` parameter, or one of its
      # ancestors. Object is excluded from the search: top-level constants
      # live on it, so a global ::Entity class is not a representer.
      # @param object [Object] the object to locate the Entity class for
      # @return [Class] the located Entity class, or nil if none is found
      def entity_class_for_obj(object)
        entity_for_class(object.class) || entity_for_class(element_class(object))
      end

View on GitHub (pinned to 22d7975629)

Solutions

  1. Present collections under a key so the wrapper Hash is mergeable: `present :cars, cars, with: CarEntity`.
  2. Use the `root:` option to wrap the representation in a Hash: `present cars, with: CarEntity, root: 'cars'`.
  3. Present a single composite entity for the whole response, or build the response hash manually and present it once.

Example fix

# before
get '/dashboard' do
  present user, with: UserEntity
  present cars, with: CarEntity # Array cannot be merged
end

# after
get '/dashboard' do
  present :user, user, with: UserEntity
  present :cars, cars, with: CarEntity
end
Defensive patterns

Strategy: validation

Validate before calling

# Keyed presents always merge (the wrapper is a Hash), so prefer them for compound bodies
present :user, user, with: UserEntity
present :cars, cars, with: CarEntity

Type guard

# before a second bare present of a collection, check mergeability of the entity output
representation = CarEntity.represent(cars)
raise ArgumentError, 'use a key/root for collection entities' unless representation.respond_to?(:merge)

Prevention

When it happens

Trigger: Two `present` calls in one endpoint where the later one presents a collection with an entity: `present user, with: UserEntity` followed by `present cars, with: CarEntity` (the second representation is an Array). Presenting any entity whose root-level output is not a Hash when a body is already set.

Common situations: Building a compound response (user + their items) by calling present once per section. Returning an array entity after a `present status_message` style call. Migration from single-object endpoints to endpoints that also include collections.

Related errors


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