Navigation destination that matches request NavDeepLinkRequest cannot be found in the navigation graph NavGraph
Asked Answered
G

4

21

I have a NavGraph that looks like this:

@Composable
fun NavGraph (
    navController: NavHostController
) {
    NavHost(
        navController = navController,
        startDestination = "Products"
    ) {
        composable(
            route = "Products"
        ) {
            ProductsScreen(
                navController = navController
            )
        }
        composable(
            route = "Product Details",
            arguments = listOf(
                navArgument("product") {
                    type = NavType.SerializableType(Product::class.java)
                }
            )
        ) {
            val product = navController.previousBackStackEntry?.arguments?.getSerializable("product") as Product
            ProductDetailsScreen(
                navController = navController,
                product = product
            )
        }
    }
}

Inside the ProductDetailsScreen, I want on product click to navigate further to details screen passing a Product object:

LazyColumn {
    items(
        items = products
    ) { product ->
        ProductCard(
            product = product,
            onProductClick = {
                navController.currentBackStackEntry?.arguments?.putSerializable("product", product)
                navController.navigate("Product Details")
            }
        )
    }
}

The products are perfectly displayed but when I click on a product, the app crashes with this error:

java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/Product Details } cannot be found in the navigation graph NavGraph(0x0) startDestination={Destination(0xb543811) route=Products}

Can anyone help?

P.S. I also followed this answer but no luck :(

Gotama answered 11/1, 2022 at 14:20 Comment(6)
You may remove space. Change "Product Details" -> "Product_Details" for exampleViosterol
@Viosterol Thanks for commenting. I just did, and doesn't work. I have even removed the entire second word (Details) + along with the white space and behaves the same. Any other idea?Gotama
Sure) Just remove all params and open an empty screen. like "Products". If it works you can add a paramViosterol
@Viosterol Yes, if I remove them, I can open ProductDetailsScreen.Gotama
@JoanP. did you find any solution? Have the same problem and seems like nothing helps >_<Chemist
@EugeneTroyanskii No, I did not.Gotama
G
13

Make sure you have all the argument names and route names correctly setup and avoid spaces, use underscores when you want to break words

My Mistake

The argument name in the route definition and while supplying in the navArgument block should be same

composable(
                        "pokemon_detail_screen/{dominantColor}/{pokemonName}", //Notice over here
                        arguments = listOf(
                            navArgument("dominantColor") {
                                type = NavType.IntType
                            },
                            navArgument("pokemon_name") { // Notice over here
                                type = NavType.StringType
                            }
                        )
                    )

Took me quite some time to figure it out so be very careful

Guyette answered 30/5, 2022 at 14:32 Comment(0)
A
13

I had this error when i was using json as string to pass class to my navigation here is how i implemented :

 composable(
            "details/{MyObject}",
            arguments = listOf(navArgument("MyObject") {
                type = NavType.StringType
            })
        ) {
            it.arguments?.getString("MyObject")?.let { jsonString ->
                var issue = MyObject()
                if (!jsonString.isNullOrEmpty())
                    issue = jsonString.fromJson(MyObject::class.java)
                DetailsView(navController = navController, detailsViewModel, myObject = MyObject)
            }
        }

And how i call it :

val gson = Gson()
var myObjectString = gson.toJson(myObject, MyObject::class.java)
navController.navigate("details/$myObjectString")

And here sometime i was getting the Navigation destination that matches request NavDeepLinkRequest cannot be found in the navigation graph NavGraph error and sometimes i didn't got it. it was depending on the object i was clicking.

I think it's because some of my data was not well formed when i got the answer from the api meaning i might have some unwanted characters when i was transforming it to json. To avoid that i encoded my json in utf8 like so :

var encode = URLEncoder.encode(myObjectString,StandardCharsets.UTF_8.toString())
navController.navigate("details/$encode")

Then i didn't got the navigation error again, i hope that could help people that are trying to use jetpack compose navigation with json to send object

Agouti answered 21/3, 2023 at 15:37 Comment(1)
Thanks, I just had to use Uri.encode(json) instead of URLEncoder.encodeUninstructed
R
1

This answer explains really good how to pass a parcelable argument with compose navigation.

The error message you describe above that the navigation destination that matches request NavDeepLinkRequest cannot be found in the navigation graph NavGraph can also appear when you want to hand over an optional argument and forget to make it nullable.

  arguments: List<NamedNavArgument> = listOf(
            navArgument("product") {
                type = Product.NavigationType //check out the linked answer to know how to write the Product.NavigationType
                nullable = true
            }
        )
Reck answered 7/4, 2022 at 8:14 Comment(1)
This is my situation. I set the deeplink for that Composable but forget to make an argument to be nullable. After setting it, everything works.Schroth
V
0

It is my sample

@ExperimentalPagerApi
@Composable
fun WallNavigation(nameFolder: String, paths: List<String>) {
   val navController = rememberNavController()
   val model: ImageViewModel = viewModel()
   model.setFolder(nameFolder)
   model.setFileNames(paths)

   NavHost(navController = navController, startDestination = Screen.MainScreen.route) {
    composable(Screen.MainScreen.route) {
        MainScreen(navController = navController, model)
    }

    composable(route = Screen.GalleryScreen.route + "/{position}", arguments = listOf(navArgument(name = "position") {
        type = NavType.IntType
        defaultValue = -1
        nullable = false
    })) { entity ->
        GalleryScreen(navController = navController, position = entity.arguments?.getInt("position") ?: -1, imageViewModel = model)
    }

    composable(route = Screen.CropScreen.route) {
        CropScreen(navController = navController, imageViewModel = model)
    }
  }
} 

sealed class Screen(val route : String) {
    object MainScreen : Screen("main_screen")
    object GalleryScreen : Screen("gallery_screen")
    object CropScreen : Screen("crop_screen")

    fun withArgs(vararg args: String):String {
       return buildString {
          append(route)
          args.forEach { arg ->
              append("/$arg")
          }
        }
     }
}
Viosterol answered 12/1, 2022 at 13:3 Comment(10)
Let me try to understand and get back to you. ThanksGotama
Unfortunately, it doesn't work for me, as I need to send an entire object of type Product from one screen to another.Gotama
@JoanP. No problem, just use ViewModel. You can sen id of a product. Whole the product you can get from ViewModel. I do the same action in my sample.Viosterol
@JoanP. The equal problem #67121933Viosterol
Are you also converting it to JSON string too? Voted up for your effort.Gotama
@JoanP. No. I have a list in ViewModel. Also, you can use a single ViewModel for "Products" and "Product Detail" screens. I guess you a place where you saving the list of products. Add a method "fun getDetail(id: String): Product" in the placeViosterol
Let us continue this discussion in chat.Viosterol
No, I'm not using fun getDetail(id: String): Product. Why? Because don't need that. All data that I need is inside the object that I want to pass to the other screen. I don't need any other request.Gotama
Sure, You don't need another request. You have a response. Why do you use it a second time? I guess you have a repository for the response.Viosterol
I think this guy over here, just answered my new question, and it makes sense. Thanks for you time and effort.Gotama

© 2022 - 2024 — McMap. All rights reserved.