getgrav/grav · error · InvalidArgumentException
%s: Relationship %s does not exist
Error message
%s: Relationship %s does not exist
What it means
The Flex user object's relationship lookup (UserObject.php:727) only resolves two built-in relationships: 'media' (a list of buildMediaObject entries) and 'avatar'. Any other name falls through the switch to an InvalidArgumentException formatted as '%s: Relationship %s does not exist'. It signals that the requested relation name is not part of the user flex type's schema — unlike pages or other flex types, users expose no other relations.
Source
Thrown at system/src/Grav/Common/Flex/Types/Users/UserObject.php:727
* @param string $name
* @return array|object|null
* @internal
*/
public function initRelationship(string $name)
{
switch ($name) {
case 'media':
$list = [];
foreach ($this->getMedia()->all() as $filename => $object) {
$list[] = $this->buildMediaObject(null, $filename, $object);
}
return $list;
case 'avatar':
return $this->buildMediaObject('avatar', basename($this->getAvatarUrl()), $this->getAvatarImage());
}
throw new \InvalidArgumentException(sprintf('%s: Relationship %s does not exist', $this->getFlexType(), $name));
}
/**
* @return bool Return true if relationships were updated.
*/
protected function updateRelationships(): bool
{
$modified = $this->getRelationships()->getModified();
if ($modified) {
foreach ($modified as $relationship) {
$name = $relationship->getName();
switch ($name) {
case 'avatar':
\assert($relationship instanceof ToOneRelationshipInterface);
$this->updateAvatarRelationship($relationship);
break;
default:
throw new \InvalidArgumentException(sprintf('%s: Relationship %s cannot be modified', $this->getFlexType(), $name), 400);View on GitHub (pinned to 6040efed04)
Solutions
- Request only 'media' or 'avatar' from user flex objects — those are the two names this type implements.
- Whitelist the relationship name before calling the API: in_array($name, ['media', 'avatar'], true) and reject others with your own clear error.
- If you genuinely need custom relationships on users, subclass UserObject, register the subclass as the directory's data.object class, and extend the switch with your cases.
Example fix
// before
$rel = $user->getRelationship($name); // InvalidArgumentException for anything but media/avatar
// after
$rel = in_array($name, ['media', 'avatar'], true) ? $user->getRelationship($name) : null;
if (null === $rel) {
// unknown relationship — handle gracefully (404 / ignore)
} Defensive patterns
Strategy: type-guard
Validate before calling
$allowed = ['media', 'avatar'];
if (!in_array($name, $allowed, true)) {
// reject early: unknown relationship for user flex objects
} Type guard
function isKnownUserRelationship(string $name): bool
{
return \in_array($name, ['media', 'avatar'], true);
} Try / catch
try {
$rel = $user->getRelationship($name);
} catch (\InvalidArgumentException $e) {
// 404/400: relationship not supported by this flex type
} Prevention
- Treat relationship names as a closed set per flex type; never forward client input verbatim.
- Keep the whitelist in one constant shared by endpoint validation and rendering.
- After Grav upgrades, re-check which relationships the user type implements before adding calls.
When it happens
Trigger: Calling the relationship getter with anything other than 'media' or 'avatar' — e.g. 'groups' (groups are a plain property on user data, not a relationship), 'Avatar' (wrong case), or a typo like 'medai'; a REST-style endpoint that forwards a client-supplied relationship name straight into this method.
Common situations: Plugins that assume every flex type supports the same relationship names; admin customizations copying relationship code from a different flex type; client code written against a newer/older Grav where the set of relationships differs.
Related errors
- 400
- __METHOD__(): You need to pass option 'directory'
- __METHOD__(): 'object' should be instance of FlexObjectInter
- __METHOD__(): 'directory' should be instance of FlexDirector
- Passwords did not match.
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/0e00c54ee997fc3e.
Report an issue: GitHub.