NavController crashes with 'No destination on back stack' when navigating to camera route inside nested navigation graph

20 hours ago 2
ARTICLE AD BOX

I have a nested navigation graph (REG_GROUP) that contains registration screens and a photoGraph extension with camera and photo_preview destinations. When I open a bottom sheet and tap "Camera" or select a photo from gallery, the app crashes.

Error:

java.lang.IllegalArgumentException: No destination with ID -864236036 is on the NavController's back stack. The current destination is Destination(0x9a9104f2) route=camera at androidx.navigation.NavController.getBackStackEntry(NavController.kt:2209) at androidx.navigation.NavController.addEntryToBackStack(NavController.kt:1918) at androidx.navigation.NavController.navigate(NavController.kt:1984) at com.example.repairkz.common.handlers.PhotoPickerHandlerKt.photoPickerHandler$lambda$6$lambda$5(PhotoPickerHandler.kt:58) at com.example.repairkz.ui.features.auth.signUp.ui.SignUpLayoutKt$SignUpLayout$1$1$1.emit(SignUpLayout.kt:94)

Steps to reproduce:

Launch app, land on SignUpData screen

Tap avatar button — bottom sheet opens

Select "Camera" → crash

Or: select from Gallery, pick photo, tap "Done" → crash

registrationGraph:

@SuppressLint("UnrememberedGetBackStackEntry") fun NavGraphBuilder.registrationGraph(navController: NavController) { navigation( startDestination = SIGN_UP_DATA, route = REG_GROUP ) { composable(route = SIGN_UP_EMAIL) { nbse -> val parentEntry = remember(nbse) { navController.getBackStackEntry(REG_GROUP) } val signUpViewModel: SignUpViewModel = hiltViewModel(parentEntry) SignUpEmail(signUpViewModel, navController) } composable(route = SIGN_UP_CODE) { nbse -> val parentEntry = remember(nbse) { navController.getBackStackEntry(REG_GROUP) } val signUpViewModel: SignUpViewModel = hiltViewModel(parentEntry) SignUpCode(signUpViewModel, navController) } composable(route = SIGN_UP_DATA) { nbse -> val parentEntry = remember(nbse) { navController.getBackStackEntry(REG_GROUP) } val signUpViewModel: SignUpViewModel = hiltViewModel(parentEntry) SignUpData(signUpViewModel, navController) } photoGraph( navController = navController, getViewModel = { navBackStackEntry -> val parentEntry = remember(navBackStackEntry) { navController.getBackStackEntry(REG_GROUP) } hiltViewModel<SignUpViewModel>(parentEntry) } ) } }

photoGraph:

fun NavGraphBuilder.photoGraph( navController: NavController, getViewModel: @Composable (NavBackStackEntry) -> CameraCapable ) { composable(Routes.CAMERA) { nbse -> val vm = getViewModel(nbse) val context = LocalContext.current Camera( context = context, takeNewPhoto = { uri -> uri?.let { vm.onPhotoSelected(it) navController.popBackStack() } } ) } composable(Routes.PHOTO_PREVIEW) { nbse -> val context = LocalContext.current val vm = getViewModel(nbse) val uri = vm.getPreviewUri() uri?.let { nonNullUri -> PhotoPreview( context, uri = nonNullUri, onDismissRequest = { navController.popBackStack() }, ) { uri -> uri?.let { vm.onPhotoSelected(it) navController.popBackStack() } } } } }

SignUpLayout (LaunchedEffect):

val action = photoPickerHandler( getPhotoFromMedia = { uri -> if (uri != null) signUpViewModel.handleIntent(SignUpIntent.GetPhotoFromMedia(uri)) }, navController = navController, context = context ) LaunchedEffect(Unit) { signUpViewModel.channel.collect { effect -> val currentRoute = navController.currentBackStackEntry?.destination?.route when (effect) { SignUpEffect.NavigateToConfirmation -> navController.navigate(SIGN_UP_CODE) is SignUpEffect.ShowSnackBar -> snackbarHostState.showSnackbar(effect.message) is SignUpEffect.NavigateToFillingData -> navController.navigate(SIGN_UP_DATA) is SignUpEffect.NavigateToMainWindow -> navController.navigate(MAIN_WINDOW) is SignUpEffect.OpenPhotoPicker -> { if (currentRoute != Routes.CAMERA && currentRoute != Routes.PHOTO_PREVIEW) { when (effect.typeOfSelect) { PhotoSourceEnum.CAMERA -> action.launchCamera() PhotoSourceEnum.GALLERY -> action.launchGallery() } } } SignUpEffect.NavigateToPreview -> { if (currentRoute != Routes.PHOTO_PREVIEW) navController.navigate(Routes.PHOTO_PREVIEW) } } } } ViewModel: private val _channel = Channel<SignUpEffect>(Channel.BUFFERED) val channel = _channel.receiveAsFlow() is SignUpIntent.ChangeAvatar -> { viewModelScope.launch { _channel.send(SignUpEffect.OpenPhotoPicker(intent.typeOfSelect)) } } is SignUpIntent.GetPhotoFromMedia -> { _uiState.value = _uiState.value.copy( userInfo = _uiState.value.userInfo.copy( photoUri = intent.uri ) ) viewModelScope.launch { _channel.send(NavigateToPreview) } }

The camera destination is registered inside registrationGraph which has route = REG_GROUP, so REG_GROUP should be on the back stack. Why does getBackStackEntry fail to find it?

Read Entire Article