{"record":{"id":"09f9b82c1ea3f7ff","repo":"NationalSecurityAgency/ghidra","slug":"not-a-zip-file-fs-getfsrl","errorCode":null,"errorMessage":"Not a zip file: \" + fs.getFSRL()","messagePattern":"Not a zip file: \" \\+ fs\\.getFSRL\\(\\)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreTask.java","lineNumber":118,"sourceCode":"\t\t\tplugin.cleanupRestoredProject(projectLocator);\n\t\t\tString eMsg = (e.getMessage() != null) ? \":\\n\\n\" + e.getMessage() : \"\";\n\t\t\tMsg.showError(this, null, \"Restore Archive Failed\",\n\t\t\t\t\"An error occurred when restoring the project archive\\n \" + projectArchiveFile +\n\t\t\t\t\t\" to \\n \" + projectDir + eMsg,\n\t\t\t\te);\n\t\t\tMsg.info(this, \"Restore Archive: \" + locInfo + \" failed.\");\n\t\t}\n\t}\n\n\tprivate void createProjectMarkerFile() throws IOException {\n\t\tif (!projectFile.createNewFile()) {\n\t\t\tthrow new IOException(\"Couldn't create file \" + projectFile.getAbsolutePath());\n\t\t}\n\t}\n\n\tprivate void verifyArchive(GFileSystem fs, TaskMonitor monitor) throws IOException {\n\t\tif (!fs.getFSRL().getProtocol().equals(\"zip\")) {\n\t\t\tthrow new IOException(\"Not a zip file: \" + fs.getFSRL());\n\t\t}\n\t\tGFile magicFile = fs.lookup(\"/\" + ArchivePlugin.JAR_VERSION_TAG);\n\t\tif (magicFile == null) {\n\t\t\tthrow new IOException(\"Missing Ghidra Project Archive (.gar) marker file\");\n\t\t}\n\t}\n\n\t@Override\n\tprotected void processFile(GFile file, File destFSFile, TaskMonitor monitor)\n\t\t\tthrows IOException, CancelledException {\n\t\tif (!shouldSkip(file)) {\n\t\t\tsuper.processFile(file, destFSFile, monitor);\n\t\t}\n\t}\n\n\t@Override\n\tprotected void processDirectory(GFile srcGFileDirectory, File destDirectory,\n\t\t\tTaskMonitor monitor) throws IOException, CancelledException {","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreTask.java#L100-L136","documentation":"Thrown as IOException by RestoreTask.verifyArchive when the supplied filesystem's FSRL protocol is not \"zip\". Ghidra project archives (.gar) are zip-based, so verifyArchive rejects anything whose underlying filesystem is not a zip filesystem before checking for the marker file.","triggerScenarios":"Passing a GFileSystem whose getFSRL().getProtocol() is anything other than \"zip\" — e.g. a local-file (\"file\") filesystem, a gzip, a tar, or a custom FS — into RestoreTask.restore/verifyArchive.","commonSituations":"User selects a non-archive file (or a plain directory/zipped-non-project file) for project-archive restore; the file extension was renamed to .gar but the content is not a zip; a wrapper filesystem layer changed the reported protocol.","solutions":["Select a genuine Ghidra project archive (.gar) created by ArchivePlugin, which is a zip.","Re-create the archive from a valid project if the file is corrupt or mis-typed.","If the FS protocol is reported incorrectly, inspect fs.getFSRL() and re-open the file through the zip filesystem layer.","Catch IOException and present a clear 'not a project archive' message to the user."],"exampleFix":"// before\nprivate void verifyArchive(GFileSystem fs, TaskMonitor monitor) throws IOException {\n    if (!fs.getFSRL().getProtocol().equals(\"zip\")) {\n        throw new IOException(\"Not a zip file: \" + fs.getFSRL());\n    }\n    ...\n}\n\n// after — re-open via zip FS before rejecting, clearer error\nprivate void verifyArchive(GFileSystem fs, TaskMonitor monitor) throws IOException {\n    if (!fs.getFSRL().getProtocol().equals(\"zip\")) {\n        fs = FileSystemService.getInstance().openFileSystem(\n            fs.getFSRL().withProtocol(\"zip\"), monitor);\n    }\n    if (!fs.getFSRL().getProtocol().equals(\"zip\")) {\n        throw new IOException(\"Selected file is not a Ghidra project archive (.gar must be zip): \" + fs.getFSRL());\n    }\n    ...\n}","handlingStrategy":"validation","validationCode":"if (!\"zip\".equals(fs.getFSRL().getProtocol())) {\n    // re-open through the zip filesystem layer or reject with a clear message\n    throw new IOException(\"Selected file is not a Ghidra project archive (must be zip): \" + fs.getFSRL());\n}","typeGuard":"boolean isZip = \"zip\".equals(fs.getFSRL().getProtocol());","tryCatchPattern":"try {\n    verifyArchive(fs, monitor);\n} catch (IOException e) {\n    Msg.showError(this, null, \"Restore Failed\", \"Not a project archive: \" + e.getMessage());\n}","preventionTips":["Select a genuine .gar produced by ArchivePlugin.","Re-create archives from a valid project when the file is mis-typed.","Present a clear 'not a project archive' error to users."],"tags":["ghidra","archive","restore","zip","io","validation"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}