The IncidentYour app builds perfectly. The Gradle sync is green. But the moment you tap a button to navigate, the app vanishes. You check Logcat to find a wall of red text: java.lang.IllegalStateException: CompositionLocal LocalNavController not provided.
This error is the Jetpack Compose version of a NullPointerException. It occurs when a Composable tries to pull a NavController from the environment, but finds nothing there. Essentially, you're asking for a tool that hasn't been put in the toolbox yet.
TL;DR: The 30-Second FixIf you use a custom LocalNavController, you must wrap your UI in a CompositionLocalProvider. This is usually done at the root of your MainActivity.
val navController = rememberNavController()
CompositionLocalProvider(LocalNavController provides navController) {
// Your App Content
MainScreen()
}
Why This HappensThink of CompositionLocal as a way to pass data down the UI tree behind the scenes. It saves you from "prop-drilling," which is the tedious process of passing a navController through ten different function parameters just to reach one button.
The crash triggers when LocalNavController.current is called, but the parent hierarchy lacks a provider. This typically stems from three specific scenarios:
- The Missing Root: You defined the
staticCompositionLocalOfbut forgot to wrap yourNavHostin the provider.- Isolated Previews: Android Studio Previews run in a vacuum. They don't know yourMainActivityexists, so they can't see the controller you defined there.- Manual Definition Errors: You might have initialized the local with anerror()block that triggers because no default value was supplied.## Step-by-Step Solutions### 1. The Global Root SetupMost developers run into this because the provider is missing at the top level. Open yourMainActivity.ktand ensure theCompositionLocalProviderwraps your entire navigation graph. UsingstaticCompositionLocalOfis best here because the controller instance rarely changes during the app's lifecycle.
// 1. Define the local (usually in a NavGraph.kt file)
val LocalNavController = staticCompositionLocalOf<NavHostController> {
error("No NavController found!")
}
// 2. Wrap your content
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) {
setContent {
val navController = rememberNavController()
CompositionLocalProvider(LocalNavController provides navController) {
AppNavigation()
}
}
}
}
}
2. Fixing the "Render Problem" in PreviewsIf your app runs on a physical device but the Preview tab shows a grey box, you need a mock provider. Previews need their own local context. Since you aren't actually navigating between screens in a static preview, a simple rememberNavController() is enough to satisfy the compiler.
@Preview(showBackground = true)
@Composable
fun MyScreenPreview() {
val mockController = rememberNavController()
CompositionLocalProvider(LocalNavController provides mockController) {
MyScreen()
}
}
3. Scoping to the NavHostIf you prefer not to make the controller global, you can wrap only the NavHost. However, be careful. Any Composable that calls LocalNavController.current outside of this specific block will still crash the app instantly.
Verification ChecklistDon't assume it's fixed just because the first screen loads. Run these three checks:
- The Cold Start: Kill the app process and restart. Ensure the initial
startDestinationloads without a hitch.- The 3-Level Test: Navigate at least three screens deep into your UI. IfLocalNavController.currentworks at the deepest level, your hierarchy is correctly configured.- Preview Rendering: Check the Design view in Android Studio. If the "Render Problem" overlay is gone, your mock provider is working.## Pro Tip: Performance MattersWhen usingCompositionLocal, preferstaticCompositionLocalOffor theNavController. Unlike a standardcompositionLocalOf, the static version doesn't track every single consumer. Since yourNavControllerinstance is usually created once and never swapped, the static version saves the overhead of unnecessary recompositions across your entire app.

