ionic-team/ionic-framework · error · Error
inserted view was already inserted
Error message
inserted view was already inserted
What it means
Thrown in IonNav.prepareTI() while validating each inserted view: a view being inserted already has `view.nav` set to a different nav instance. Views track which nav owns them; inserting a view that another nav already claims would corrupt both stacks, so the nav rejects it.
Source
Thrown at core/src/components/nav/nav.tsx:739
}
const insertViews = ti.insertViews;
if (!insertViews) {
return;
}
assert(insertViews.length > 0, 'length can not be zero');
const viewControllers = convertToViews(insertViews);
if (viewControllers.length === 0) {
throw new Error('invalid views to insert');
}
// Check all the inserted view are correct
for (const view of viewControllers) {
view.delegate = ti.opts.delegate;
const nav = view.nav;
if (nav && nav !== this) {
throw new Error('inserted view was already inserted');
}
if (view.state === VIEW_STATE_DESTROYED) {
throw new Error('inserted view was already destroyed');
}
}
ti.insertViews = viewControllers;
}
/**
* Returns the view that will be entered considering the transition instructions.
*
* @param ti The instructions.
* @param leavingView The view being left or undefined if none.
*
* @returns The view that will be entered, undefined if none.
*/
private getEnteringView(
ti: TransitionInstruction,View on GitHub (pinned to 625f9c38ad)
Solutions
- Do not pass live ViewController instances between navs; pass the underlying component and let the target nav create a fresh view.
- If you genuinely need to move a view, pop it from the source nav first and then insert the component (not the controller) into the target.
- Use `nav.getByIndex`/`getActive` only to read state, never to relocate the controller into another nav.
- Audit code that calls `insert`/`insertPages` for any controller obtained from `getViews()`/`getActive()`.
Example fix
// before
const view = otherNav.getActive();
await thisNav.insert(0, view);
// after
const { component, componentProps } = view;
await otherNav.removeIndex(otherNav.getViews().indexOf(view), 1);
await thisNav.insert(0, component, componentProps); Defensive patterns
Strategy: validation
Validate before calling
// Never pass a live controller to another nav; insert the component instead
if (viewController.nav && viewController.nav !== nav) {
throw new Error('View already belongs to another nav. Insert its component instead.');
}
await nav.insert(0, viewController.component, viewController.componentProps); Type guard
function isOwnedBy(view: ViewController, nav: HTMLIonNavElement): boolean {
return !view.nav || view.nav === nav;
} Prevention
- Pass component references, not ViewController instances, when moving between navs.
- Treat getActive()/getByIndex() results as read-only; do not relocate them.
- Audit nested-nav code for any controller sharing.
When it happens
Trigger: Passing a ViewController to `insert`/`push`/`setPages` that was obtained from another IonNav (e.g. via `nav.getActive()` on a sibling) without detaching it first; reusing a live ViewController instance across two navs.
Common situations: Sharing a view reference between a parent and child IonNav; manually constructing/obtaining a ViewController and pushing it into a second nav; advanced nested-nav setups that move views between stacks.
Related errors
- removeView was not found
- no views in the stack to be removed
- invalid views to insert
- inserted view was already destroyed
- navigation stack needs at least one root page
AI-assisted analysis of ionic-team/ionic-framework@625f9c38ad (2026-08-12).
Data as JSON: /api/errors/dca7cfc96f2fd64b.
Report an issue: GitHub.