Fix ActivityNotFoundException: No Activity Found to Handle Intent on Android

intermediate๐Ÿ“ฑ Android2026-05-13| Android (API 1+), affects all versions โ€” stricter package visibility on Android 11+ (API 30+)

Error Message

android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=... }
#intent#activity#manifest#implicit-intent

What Just Happened

Your app called startActivity(intent) with an implicit intent, and Android drew a blank โ€” no installed app declared an intent filter matching what you asked for. The crash shows up in logcat like this:

android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=https://example.com }
  at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2105)
  at android.app.Instrumentation.execStartActivity(Instrumentation.java:1747)
  at android.app.Activity.startActivity(Activity.java:5258)

This isn't a permissions error or a manifest misconfiguration on your side. No app on the device declared an intent filter for what you're asking. Still, there are a few specific reasons this happens even on devices where you'd expect it to just work.

Debug Process

1. Confirm the exact intent being fired

Log your intent before calling startActivity:

Log.d("IntentDebug", intent.toString());

Look closely at three things: Is the action correct? Is the URI scheme right โ€” https:// vs http:// vs a custom scheme like myapp://? Is a MIME type set when it shouldn't be, or missing when the handler requires it?

2. Check if any app can handle it

Call resolveActivity() before you ever touch startActivity():

if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
} else {
    Log.e("IntentDebug", "No handler found for: " + intent.toString());
    Toast.makeText(this, "No app found to handle this action", Toast.LENGTH_SHORT).show();
}

A null result confirms the problem. On Android 11+, null can also mean the target app exists but isn't visible to your app โ€” more on that below.

3. Android 11+ package visibility (the sneaky one)

API 30 introduced package visibility filtering. Even if Chrome or Gmail is installed, your app can't query it without declaring the intent in a <queries> block in your manifest. Skip that block and resolveActivity() returns null โ€” even on a device that has a perfectly capable browser sitting right there. This is the most common cause on devices running Android 11 and up.

Solutions

Fix 1: Add to AndroidManifest.xml (Android 11+)

Declare the intent patterns your app needs to query. Here are the three you'll hit most often:

<!-- Open URLs in browser -->
<queries>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="https" />
    </intent>
</queries>
<!-- Send email -->
<queries>
    <intent>
        <action android:name="android.intent.action.SENDTO" />
        <data android:scheme="mailto" />
    </intent>
</queries>
<!-- Dial phone number -->
<queries>
    <intent>
        <action android:name="android.intent.action.DIAL" />
        <data android:scheme="tel" />
    </intent>
</queries>

You can stack multiple <intent> blocks inside a single <queries> element. One important placement detail: <queries> must be a direct child of <manifest>, not nested inside <application>.

Fix 2: Wrap startActivity in try/catch

Even with <queries> in place, a defensive try/catch saves you on edge cases. Budget Android devices โ€” especially those running stripped OEM ROMs from manufacturers like Lava or Tecno โ€” sometimes ship without any default browser or email client:

try {
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"));
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    Toast.makeText(this, "No browser installed", Toast.LENGTH_SHORT).show();
}

In Kotlin:

val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
try {
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    Toast.makeText(this, "No app found to open this link", Toast.LENGTH_SHORT).show()
}

Fix 3: Use Intent.createChooser for sharing

For ACTION_SEND, the chooser usually shows an empty dialog instead of crashing. But if zero apps are visible due to the API 30 visibility rules, it still throws. Cover both bases:

Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "Check this out!");

Intent chooser = Intent.createChooser(shareIntent, "Share via");
if (shareIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

Add the matching query to your manifest:

<queries>
    <intent>
        <action android:name="android.intent.action.SEND" />
        <data android:mimeType="text/plain" />
    </intent>
</queries>

Fix 4: Custom URI scheme with no handler

Custom schemes like myapp://action fail hard when the target app isn't installed. Resolve it before firing, and have a web fallback ready:

Uri customUri = Uri.parse("myapp://open/profile/123");
Intent deepLink = new Intent(Intent.ACTION_VIEW, customUri);

if (deepLink.resolveActivity(getPackageManager()) != null) {
    startActivity(deepLink);
} else {
    // App not installed โ€” fall back to web
    Intent fallback = new Intent(Intent.ACTION_VIEW, Uri.parse("https://myapp.com/profile/123"));
    startActivity(fallback);
}

Verification

Run the app on a real device โ€” emulators can mask visibility issues that only surface on physical hardware. Confirm these four things:

  • The intent resolves without crashing.
  • Logcat shows no ActivityNotFoundException stack trace.
  • The flow works on a device running Android 11+ (API 30), where the visibility rules actually bite.
  • Your fallback path triggers correctly on a minimal-apps device or a GApps-free emulator image.

Want to verify your <queries> block is working? Dump what your app can actually see at runtime:

// Kotlin โ€” list all apps that can handle ACTION_VIEW for https
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
val activities = packageManager.queryIntentActivities(intent, 0)
activities.forEach { Log.d("PM", it.activityInfo.packageName) }

Empty list despite adding <queries>? Double-check the scheme โ€” https and http are treated as separate entries and need to be declared separately.

Lessons Learned

  • Implicit intents without a null check or try/catch are a ticking time bomb. Android device diversity is brutal โ€” you cannot assume any specific app is installed, even Chrome.
  • Android 11+ made package visibility opt-in, not opt-out. Every implicit intent your app fires needs a matching <queries> entry. Without it, resolveActivity() returns null even when the target app is sitting right there on the device.
  • Factory-reset and low-end devices expose holes in your fallback logic. Budget phones often lack a default browser, email client, or map app. If your fallback is just a comment in the code, it's not a fallback.
  • One mental model that helps: <queries> is not about permissions. You're not asking Android for access โ€” you're telling it which intent filters your app needs to be aware of at query time.

Related Error Notes