getgrav/grav · warning · RuntimeException
Failed: Cannot set page parent to self
Error message
Failed: Cannot set page parent to self
What it means
FlexPageObject::move() validates the target parent before doing anything; if the new parent's route equals the page's own route (i.e. you are setting the page as its own parent), it throws 'Cannot set page parent to self'. The check compares routes, so aliases or duplicates resolving to the same route also trigger it. It is a self-reference guard, not a storage failure.
Source
Thrown at system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php:275
*/
public function file(): ?MarkdownFile
{
// TODO:
throw new RuntimeException(__METHOD__ . '(): Not Implemented');
}
/**
* Prepare move page to new location. Moves also everything that's under the current page.
*
* You need to call $this->save() in order to perform the move.
*
* @param PageInterface $parent New parent page.
* @return $this
*/
public function move(PageInterface $parent)
{
if ($this->route() === $parent->route()) {
throw new RuntimeException('Failed: Cannot set page parent to self');
}
$rawRoute = $this->rawRoute();
if ($rawRoute && Utils::startsWith($parent->rawRoute(), $rawRoute)) {
throw new RuntimeException('Failed: Cannot set page parent to a child of current page');
}
$this->storeOriginal();
// TODO:
throw new RuntimeException(__METHOD__ . '(): Not Implemented');
}
/**
* Prepare a copy from the page. Copies also everything that's under the current page.
*
* Returns a new Page object for the copy.
* You need to call $this->save() in order to perform the move.
*View on GitHub (pinned to 6040efed04)
Solutions
- Guard the call: if ($parent->route() !== $page->route()) { $page->move($parent); }.
- In move forms, exclude the page itself (and its descendants) from the selectable parents.
- If the goal was only reordering among siblings, use the ordering/metadata API instead of move().
Example fix
// before
$page->move($selectedParent);
// after
if ($selectedParent->route() !== $page->route()) {
$page->move($selectedParent);
} Defensive patterns
Strategy: validation
Validate before calling
// Reject a no-op self-move before calling the API
if ($parent->route() !== $page->route()) {
$page->move($parent);
$page->save();
} Try / catch
try {
$page->move($parent);
} catch (\Grav\Framework\Flex\Exception\RuntimeException $e) {
if (str_contains($e->getMessage(), 'Cannot set page parent to self')) {
// treat as no-op: user re-selected the current parent
return; // or show a notice
}
throw $e;
} Prevention
- Exclude the page itself from parent-selection dropdowns in move UIs.
- Compare routes before calling move().
- Treat same-parent selections as cancel/no-op in form handlers.
When it happens
Trigger: Calling $page->move($page); passing a parent object that is actually the same page fetched again (e.g. via a route lookup that resolves back to it); forms that let users pick a parent and default the selection to the current page.
Common situations: Admin page-move UIs where the current page appears in the parent dropdown; programmatic tree restructuring with index math that can select the node itself.
Related errors
- Failed: Cannot set page parent to a child of current page
- Grav\Framework\Flex\Pages\Traits\PageLegacyTrait::init(): No
- Grav\Framework\Flex\Pages\Traits\PageLegacyTrait::raw(string
- Grav\Framework\Flex\Pages\Traits\PageLegacyTrait::file(): No
- No backups defined...
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/704e2c107da42508.
Report an issue: GitHub.