getgrav/grav · error · RuntimeException

Object has to be type %s, %s given

Error message

Object has to be type %s, %s given

What it means

MediaIdentifier is typed: each identifier belongs to exactly one media type (e.g. 'page', 'account', a Flex type). setObject() rejects any MediaObjectInterface instance whose getType() does not equal the identifier's own type, throwing RuntimeException 'Object has to be type X, Y given'. It prevents pairing an object with an identifier of a different stream family, which would corrupt later resolution/caching.

Source

Thrown at system/src/Grav/Framework/Media/MediaIdentifier.php:100

            if (!isset($this->object)) {
                throw new \RuntimeException(sprintf('Object not found for identifier {type: "%s", id: "%s"}', $type, $id));
            }
        }

        return $this->object;
    }

    /**
     * @param T $object
     */
    public function setObject(MediaObjectInterface $object): void
    {
        $type = $this->getType();
        $objectType = $object->getType();

        if ($type !== $objectType) {
            throw new \RuntimeException(sprintf('Object has to be type %s, %s given', $type, $objectType));
        }

        $this->object = $object;
    }

    protected function findFlash(array $parts): ?array
    {
        $type = array_shift($parts);
        if ($type === 'account') {
            /** @var UserInterface|null $user */
            $user = Grav::instance()['user'] ?? null;
            $folder = $user->getMediaFolder();
        } else {
            $folder = 'tmp://';
        }

        if (!$folder) {
            return null;

View on GitHub (pinned to 6040efed04)

Solutions

  1. Compare $identifier->getType() with $object->getType() before assigning and only call setObject() when they match.
  2. If you hold a heterogeneous collection, group objects by getType() and match each identifier against its own group.
  3. For custom MediaObjectInterface implementations, make getType() return exactly the type string used by the corresponding MediaIdentifier scheme.
  4. If the intent is cross-type replacement, build a new MediaIdentifier for the object's type instead of forcing setObject() on the old one.

Example fix

// before
$identifier->setObject($mediaObject); // 'page' identifier + 'flex' object -> throws

// after
if ($identifier->getType() === $mediaObject->getType()) {
    $identifier->setObject($mediaObject);
} else {
    $identifier = MediaIdentifier::fromObject($mediaObject) ?? $identifier;
}
Defensive patterns

Strategy: type-guard

Validate before calling

if ($identifier->getType() === $mediaObject->getType()) {
    $identifier->setObject($mediaObject);
}

Type guard

/** @param array{identifier: \Grav\Framework\Media\MediaIdentifier, object: \Grav\Framework\Media\MediaObjectInterface} $pair */
function objectMatchesIdentifier(array $pair): bool
{
    return $pair['identifier']->getType() === $pair['object']->getType();
}

Try / catch

try {
    $identifier->setObject($mediaObject);
} catch (\RuntimeException $e) {
    if (str_starts_with($e->getMessage(), 'Object has to be type')) {
        // re-lookup an identifier matching this object's type
        $identifier = \Grav\Framework\Media\MediaIdentifier::fromObject($mediaObject) ?? $identifier;
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: Calling $identifier->setObject($obj) where $identifier was created for scheme 'page://' but $obj is a Flex media object (type 'flex' or a Flex type name), or vice versa; caching MediaObjects keyed by identifier and replaying them onto identifiers of another type; mixing custom MediaObjectInterface implementations with mismatched getType() return values.

Common situations: Custom code that bulk-assigns media objects to identifiers after a bulk fetch, sorting/grouping them by file name rather than by type; refactoring that changed the order of arguments; a custom MediaObject class returning an unexpected type string from getType().

Related errors


AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17). Data as JSON: /api/errors/d070597b6bdbefd0. Report an issue: GitHub.