cakephp/cakephp · error · DatabaseException
Cannot set a node's parent as itself.
Error message
Cannot set a node's parent as itself.
What it means
TreeBehavior::beforeSave() rejects a save where the entity's parent_id points at the entity itself, which would create a self-referencing cycle and corrupt the MPTT tree (left/right bounds). The save is aborted with a DatabaseException instead of persisting the invalid hierarchy.
Solutions
- Do not set the entity's parent field to its own primary key; omit the parent field or set it to a different node's id.
- Validate the parent id against the entity's primary key before assigning it and before saving.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at src/ORM/Behavior/TreeBehavior.php:114 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of cakephp/cakephp@1128eba9b0 (2026-09-12).
Data as JSON: /api/errors/78c428eecb27cfbe.
Report an issue: GitHub.
Appendix: source
Thrown at src/ORM/Behavior/TreeBehavior.php:114
* Transparently manages setting the lft and rght fields if the parent field is
* included in the parameters to be saved.
*
* @param \Cake\Event\EventInterface<\Cake\ORM\Table> $event The beforeSave event that was fired
* @param \Cake\Datasource\EntityInterface $entity the entity that is going to be saved
* @return void
* @throws \Cake\Database\Exception\DatabaseException if the parent to set for the node is invalid
*/
public function beforeSave(EventInterface $event, EntityInterface $entity): void
{
$isNew = $entity->isNew();
$config = $this->getConfig();
$parent = $entity->get($config['parent']);
$primaryKey = $this->_getPrimaryKey();
$dirty = $entity->isDirty($config['parent']);
$level = $config['level'];
if ($parent && $entity->get($primaryKey) === $parent) {
throw new DatabaseException("Cannot set a node's parent as itself.");
}
if ($isNew) {
if ($parent) {
$parentNode = $this->_getNode($parent);
$edge = $parentNode->get($config['right']);
$entity->set($config['left'], $edge);
$entity->set($config['right'], $edge + 1);
$this->_sync(2, '+', ">= {$edge}");
if ($level) {
$entity->set($level, $parentNode[$level] + 1);
}
return;
}
$edge = $this->_getMax();View on GitHub (pinned to 1128eba9b0)