Nested ion-tabs work but error with Cannot match any routes. URL Segment x

I have a nested Tabs situation where the tabs physically work and routing works but there’s an error in the console of:

ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: ____

Weirdly it all works and functions fine. Just this console error is annoying!

My setup is:

 Main (with set of tabs for):
    Home (/home)
    Meetings (/meetings)
    Rooms (/rooms)
       Room (/room/:id) (with set of tabs for):
           People (/room/:id/people)
           Settings (/room/:id/settings)

Main routing (page with tabs):

const routes: Routes = [
  {
    path: '',
    component: MainPage,
    children: [
      {
        path: 'home',
        loadChildren: () => import('./pages/home/home.module').then((m) => m.HomePageModule),
      },
      {
        path: 'meetings',
        loadChildren: () => import('./pages/meetings/meetings.module').then((m) => m.MeetingsPageModule),
      },
      {
        path: 'rooms',
        loadChildren: () => import('./pages/rooms/rooms.module').then((m) => m.RoomsPageModule),
      },
      {
        path: '',
        pathMatch: 'full',
        redirectTo: 'home',
      },
    ],
  },
];

Rooms routing:

{
  path: '',
  component: RoomsPage,
},
{
  path: ':id',
  loadChildren: () => import('./room/room.module').then((m) => m.RoomPageModule),
},

Room page (page with tabs):

{
  path: '',
  component: RoomPage,
  children: [
    {
      path: 'people',
      component: PeoplePage,
    },
    {
      path: 'settings',
      component: SettingsPage,
    },
    {
      path: '',
      redirectTo: 'people',
      pathMatch: 'full',
    },
  ],
},

turning on route tracing I see it successfully navigate between the nested set of tabs by pressing the buttons on it but then a second NavigationStart event is fired for an absolute path, i.e. /people which will obviously fail. No where in my code do I have such a trigger?

Router Event: NavigationStart platform-browser.js:71
NavigationStart(id: 5, url: '/rooms/1/people') platform-browser.js:66
Object { id: 5, url: "/rooms/1/people", navigationTrigger: "imperative", restoredState: null }
platform-browser.js:66
Router Event: RoutesRecognized platform-browser.js:71
RoutesRecognized(id: 5, url: '/rooms/1/people', urlAfterRedirects: '/rooms/1/people', state: Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'rooms', path:'rooms') { Route(url:'1', path:':id') { Route(url:'', path:'') { Route(url:'people', path:'people') }  }  }  }  }  } ) platform-browser.js:66
Object { id: 5, url: "/rooms/1/people", urlAfterRedirects: "/rooms/1/people", state: {…} }
platform-browser.js:66
Router Event: GuardsCheckStart platform-browser.js:71
GuardsCheckStart(id: 5, url: '/rooms/1/people', urlAfterRedirects: '/rooms/1/people', state: Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'rooms', path:'rooms') { Route(url:'1', path:':id') { Route(url:'', path:'') { Route(url:'people', path:'people') }  }  }  }  }  } ) platform-browser.js:66
Object { id: 5, url: "/rooms/1/people", urlAfterRedirects: "/rooms/1/people", state: {…} }
platform-browser.js:66
Router Event: ChildActivationStart platform-browser.js:71
ChildActivationStart(path: '') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ActivationStart platform-browser.js:71
ActivationStart(path: 'people') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: GuardsCheckEnd platform-browser.js:71
GuardsCheckEnd(id: 5, url: '/rooms/1/people', urlAfterRedirects: '/rooms/1/people', state: Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'rooms', path:'rooms') { Route(url:'1', path:':id') { Route(url:'', path:'') { Route(url:'people', path:'people') }  }  }  }  }  } , shouldActivate: true) platform-browser.js:66
Object { id: 5, url: "/rooms/1/people", urlAfterRedirects: "/rooms/1/people", state: {…}, shouldActivate: true }
platform-browser.js:66
Router Event: ResolveStart platform-browser.js:71
ResolveStart(id: 5, url: '/rooms/1/people', urlAfterRedirects: '/rooms/1/people', state: Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'rooms', path:'rooms') { Route(url:'1', path:':id') { Route(url:'', path:'') { Route(url:'people', path:'people') }  }  }  }  }  } ) platform-browser.js:66
Object { id: 5, url: "/rooms/1/people", urlAfterRedirects: "/rooms/1/people", state: {…} }
platform-browser.js:66
Router Event: ResolveEnd platform-browser.js:71
ResolveEnd(id: 5, url: '/rooms/1/people', urlAfterRedirects: '/rooms/1/people', state: Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'rooms', path:'rooms') { Route(url:'1', path:':id') { Route(url:'', path:'') { Route(url:'people', path:'people') }  }  }  }  }  } ) platform-browser.js:66
Object { id: 5, url: "/rooms/1/people", urlAfterRedirects: "/rooms/1/people", state: {…} }
platform-browser.js:66
Router Event: ActivationEnd platform-browser.js:71
ActivationEnd(path: 'people') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ChildActivationEnd platform-browser.js:71
ChildActivationEnd(path: '') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ActivationEnd platform-browser.js:71
ActivationEnd(path: '') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ChildActivationEnd platform-browser.js:71
ChildActivationEnd(path: ':id') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ActivationEnd platform-browser.js:71
ActivationEnd(path: ':id') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ChildActivationEnd platform-browser.js:71
ChildActivationEnd(path: 'rooms') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ActivationEnd platform-browser.js:71
ActivationEnd(path: 'rooms') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ChildActivationEnd platform-browser.js:71
ChildActivationEnd(path: '') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ActivationEnd platform-browser.js:71
ActivationEnd(path: '') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ChildActivationEnd platform-browser.js:71
ChildActivationEnd(path: '') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ActivationEnd platform-browser.js:71
ActivationEnd(path: '') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: ChildActivationEnd platform-browser.js:71
ChildActivationEnd(path: '') platform-browser.js:66
Object { snapshot: {…} }
platform-browser.js:66
Router Event: NavigationEnd platform-browser.js:71
NavigationEnd(id: 5, url: '/rooms/1/people', urlAfterRedirects: '/rooms/1/people') platform-browser.js:66
Object { id: 5, url: "/rooms/1/people", urlAfterRedirects: "/rooms/1/people" }
platform-browser.js:66
Router Event: Scroll platform-browser.js:71
Scroll(anchor: 'null', position: 'null') platform-browser.js:66
Object { routerEvent: {…}, position: null, anchor: null }
platform-browser.js:66
Router Event: NavigationStart platform-browser.js:71
NavigationStart(id: 6, url: '/people') platform-browser.js:66
Object { id: 6, url: "/people", navigationTrigger: "imperative", restoredState: null }
platform-browser.js:66
Router Event: NavigationError platform-browser.js:71
NavigationError(id: 6, url: '/people', error: Error: Cannot match any routes. URL Segment: 'people') platform-browser.js:66
Object { id: 6, url: "/people", error: Error }

Oh boy, nested tabs are not a fun area.

So complex setups like this are something we suggest people avoid.
Aside from the confusing UX perspective (which tab am I on??), the routing setup becomes very brittle.

Since the internal logic for tabs creates a sub-routing system, adding another one on top of that is pretty complex.

I’d suggest not going with this UI

1 Like

You hit the nail on the head Mike.

I ended up moving the inner one to a separate page and using the back button ionic control. Kind of like a details page. It feel more natural and as you say, less complex.

Consider this resolved.

Don’t do complex and silly designs!