MuntashirAkon/AppManager · error · java.io.IOException
Unable to open URI
Error message
Unable to open URI
What it means
In the key-store export flow, the dialog opens the user-picked destination URI via ContentResolver.openOutputStream. If the resolver returns null (no provider can write to that URI), an IOException 'Unable to open URI' is thrown and surfaced to the user as an error toast.
Solutions
- Pick a local destination (Downloads/On-device storage) instead of a cloud provider for the export
- Re-run the picker and select a fresh, writable location rather than reusing an old URI
- Check result code and extras in onActivityResult; ensure the URI has FLAG_GRANT_READ/WRITE permissions
- Catch the IOException and show a retry prompt instead of silently failing
Example fix
// before
OutputStream os = mActivity.getContentResolver().openOutputStream(uri);
// after
OutputStream os = mActivity.getContentResolver().openOutputStream(uri, "wt");
if (os == null) {
UIUtils.displayShortToast(R.string.failed);
return;
} Defensive patterns
Strategy: try-catch
Validate before calling
// before export, verify the URI is writable
String type = getContentResolver().getType(uri);
if (type == null) { /* provider unknown; re-pick destination */ } Try / catch
try (OutputStream os = getContentResolver().openOutputStream(uri)) {
if (os == null) { /* show 'cannot write here' and re-pick */ return; }
IoUtils.copy(is, os);
} catch (IOException e) {
UIUtils.displayShortToast(R.string.failed);
} Prevention
- Prefer local destinations (Downloads) over cloud providers for exports
- Re-pick URIs instead of reusing stale ones across sessions
- Check openOutputStream()'s null return explicitly before copying
- Show actionable error toasts when provider open fails
When it happens
Trigger: Exporting the AM keystore with ACTION_CREATE_DOCUMENT when the selected target's provider returns a null OutputStream, e.g. an unexportable cloud account or a non-writable location.
Common situations: Choosing a cloud-storage document (Drive, etc.) that only grants read access, picking a location in a revoked/removed storage provider, or a stale URI from a previous session.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- ADB command did not produce
- APK files backup is requested but no APK files have been…
- Backup failed for
- Backup failed for
- Content provider has crashed.
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/8d9348fbefd7fa24.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/io/github/muntashirakon/AppManager/settings/crypto/ImportExportKeyStoreDialogFragment.java:50
import io.github.muntashirakon.AppManager.utils.ExUtils;
import io.github.muntashirakon.AppManager.utils.ThreadUtils;
import io.github.muntashirakon.AppManager.utils.UIUtils;
import io.github.muntashirakon.io.IoUtils;
public class ImportExportKeyStoreDialogFragment extends DialogFragment {
public static final String TAG = "IEKeyStoreDialogFragment";
private FragmentActivity mActivity;
private final ActivityResultLauncher<String> mExportKeyStore = registerForActivityResult(
new ActivityResultContracts.CreateDocument("application/octet-stream"), uri -> {
if (uri == null) {
dismiss();
return;
}
ThreadUtils.postOnBackgroundThread(() -> {
try (InputStream is = new FileInputStream(AM_KEYSTORE_FILE);
OutputStream os = mActivity.getContentResolver().openOutputStream(uri)) {
if (os == null) throw new IOException("Unable to open URI");
IoUtils.copy(is, os);
ThreadUtils.postOnMainThread(() -> {
UIUtils.displayShortToast(R.string.done);
ExUtils.exceptionAsIgnored(this::dismiss);
});
} catch (IOException e) {
ThreadUtils.postOnMainThread(() -> {
UIUtils.displayShortToast(R.string.failed);
ExUtils.exceptionAsIgnored(this::dismiss);
});
}
});
});
private final ActivityResultLauncher<String> mImportKeyStore = registerForActivityResult(
new ActivityResultContracts.GetContent(), uri -> {
if (uri == null) {
dismiss();
return;View on GitHub (pinned to 0152f468fc)