{"record":{"id":"5860fc4e640c7140","repo":"MuntashirAkon/AppManager","slug":"fs-root-not-found","errorCode":null,"errorMessage":"FS Root not found.","messagePattern":"FS Root not found\\.","errorType":"exception","errorClass":"FileNotFoundException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/scanner/ScannerViewModel.java","lineNumber":213,"sourceCode":"        return mApkUri;\n    }\n\n    public void setApkUri(@NonNull Uri apkUri) {\n        mApkUri = apkUri;\n    }\n\n    public List<String> getAllClasses() {\n        return mAllClasses;\n    }\n\n    public Collection<String> getNativeLibraries() {\n        return mNativeLibraries;\n    }\n\n    public Uri getUriFromClassName(String className) throws FileNotFoundException {\n        Path fsRoot = VirtualFileSystem.getFsRoot(mDexVfsId);\n        if (fsRoot == null) {\n            throw new FileNotFoundException(\"FS Root not found.\");\n        }\n        return fsRoot.findFile(className.replace('.', '/') + \".smali\").getUri();\n    }\n\n    @WorkerThread\n    private void cacheFileIfRequired() {\n        // Test if this path is readable\n        if (mApkFile == null || !FileUtils.canReadUnprivileged(mApkFile)) {\n            // Not readable, cache the file\n            try {\n                mApkFile = mFileCache.getCachedFile(Paths.get(mApkUri));\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    @WorkerThread","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/scanner/ScannerViewModel.java#L195-L231","documentation":"ScannerViewModel.getUriFromClassName resolves the virtual filesystem root for the DEX VFS id created during scanning. If VirtualFileSystem.getFsRoot returns null (the VFS was closed or never mounted), it throws FileNotFoundException(\"FS Root not found.\").","triggerScenarios":"Calling getUriFromClassName after the scanner's ViewModel cleared mDexVfsId / closed the VFS, or before the APK was successfully loaded, or after process death recreated the ViewModel without the VFS.","commonSituations":"Clicking a class in the scanner UI after the scan was cleared; configuration change/ViewModel recreation losing the VFS id; opening results in a stale fragment.","solutions":["Re-run the scan (or reload the APK) so the virtual filesystem is mounted before requesting a class URI.","Check VirtualFileSystem.getFsRoot(vfsId) != null before calling and re-initialize if null.","Keep the ViewModel alive/scoped to the activity lifecycle so mDexVfsId and the VFS are not cleared prematurely."],"exampleFix":"// before\nUri uri = viewModel.getUriFromClassName(className);\n// after\nPath root = VirtualFileSystem.getFsRoot(viewModel.getDexVfsId());\nif (root == null) {\n    viewModel.loadApk(apkUri); // re-mount VFS\n}\nUri uri = viewModel.getUriFromClassName(className);","handlingStrategy":"try-catch","validationCode":"Path root = VirtualFileSystem.getFsRoot(dexVfsId);\nif (root == null) {\n    throw new IllegalStateException(\"Scanner VFS not mounted; re-run the scan first.\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    Uri uri = viewModel.getUriFromClassName(className);\n} catch (FileNotFoundException e) {\n    promptRescan(); // VFS root gone; re-load the APK\n}","preventionTips":["Only call getUriFromClassName while the scanner result screen is attached and the scan is active.","Re-load the APK whenever mDexVfsId is null or the ViewModel was recreated.","Disable scanner result actions after clearing scan results."],"tags":["filesystem","lifecycle","scanner"],"backgroundTag":"file-not-found","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}