NavController crashes with 'No destination on back stack' when navigating to camera route inside nested navigation graph
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?