getgrav/grav · error · RuntimeException
Cannot create new object (Already exists)
Error message
Cannot create new object (Already exists)
What it means
FlexObject::create() is strictly for inserting new objects: it refuses to proceed when exists() reports that the storage key is already taken, throwing 'Cannot create new object (Already exists)'. The object was loaded with (or explicitly given) a key that already exists in storage, so an insert would silently overwrite it.
Source
Thrown at system/src/Grav/Framework/Flex/FlexObject.php:714
if ($files && method_exists($this, 'setUpdatedMedia')) {
$this->setUpdatedMedia($files);
}
return $this;
}
/**
* {@inheritdoc}
* @see FlexObjectInterface::create()
*/
public function create(?string $key = null)
{
if ($key) {
$this->setStorageKey($key);
}
if ($this->exists()) {
throw new RuntimeException('Cannot create new object (Already exists)');
}
return $this->save();
}
/**
* @param string|null $key
* @return FlexObject|FlexObjectInterface
*/
public function createCopy(?string $key = null)
{
$this->markAsCopy();
return $this->create($key);
}
/**
* @param UserInterface|null $userView on GitHub (pinned to 6040efed04)
Solutions
- Use save() for existing objects (update path) and create() only for new ones: $object->exists() ? $object->save() : $object->create();
- Check existence first: if ($directory->getObject($key)) { /* handle duplicate: error or pick new key */ }.
- For user-supplied keys, generate a unique variant (append -1, -2) before create().
- Guard double submissions in the form layer (unique tokens) rather than relying on the storage error.
Example fix
// before
$object->create($key); // throws when key taken
// after
if ($object->exists()) {
$object->save(); // update existing
} else {
$object->create($key);
} Defensive patterns
Strategy: validation
Validate before calling
// Decide insert vs update before touching storage
if ($object->exists()) {
$object->save(); // update path
} else {
$object->create($key); // insert path
}
// For user-chosen keys, ensure uniqueness first:
while ($directory->getObject($key) !== null) {
$key = $baseKey . '-' . $i++;
} Try / catch
try {
$object->create();
} catch (\Grav\Framework\Flex\Exception\RuntimeException $e) {
if (str_contains($e->getMessage(), 'Already exists')) {
$object->save(); // degrade to update, or surface a duplicate error
}
} Prevention
- Reserve create() for brand-new objects; use save() after loading existing ones.
- Check $object->exists() before create().
- Generate unique keys for duplicate-prone submissions (double-click, form refresh).
- Add CSRF/unique tokens to creation forms.
When it happens
Trigger: Loading an existing object ($directory->getObject($key)) and calling create() instead of save()/update(); calling create('existing-key') with a manually chosen key; race where two requests create the same slug/key concurrently and the second loses.
Common situations: Duplicate submission of an admin 'create' form (double click / refresh) reusing the same generated key; import scripts that re-run without wiping storage; frontend code that creates objects with user-supplied unique fields.
Related errors
- Invalid argument $value
- Invalid argument $element
- __METHOD__(): You need to pass option 'directory'
- Flash has no directory
- __METHOD__(): 'object' should be instance of FlexObjectInter
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/c84bbd52be7f3e91.
Report an issue: GitHub.