NationalSecurityAgency/ghidra · error · IOException

Not a zip file: " + fs.getFSRL()

Error message

Not a zip file: " + fs.getFSRL()

What it means

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.

Source

Thrown at Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreTask.java:118

			plugin.cleanupRestoredProject(projectLocator);
			String eMsg = (e.getMessage() != null) ? ":\n\n" + e.getMessage() : "";
			Msg.showError(this, null, "Restore Archive Failed",
				"An error occurred when restoring the project archive\n " + projectArchiveFile +
					" to \n " + projectDir + eMsg,
				e);
			Msg.info(this, "Restore Archive: " + locInfo + " failed.");
		}
	}

	private void createProjectMarkerFile() throws IOException {
		if (!projectFile.createNewFile()) {
			throw new IOException("Couldn't create file " + projectFile.getAbsolutePath());
		}
	}

	private void verifyArchive(GFileSystem fs, TaskMonitor monitor) throws IOException {
		if (!fs.getFSRL().getProtocol().equals("zip")) {
			throw new IOException("Not a zip file: " + fs.getFSRL());
		}
		GFile magicFile = fs.lookup("/" + ArchivePlugin.JAR_VERSION_TAG);
		if (magicFile == null) {
			throw new IOException("Missing Ghidra Project Archive (.gar) marker file");
		}
	}

	@Override
	protected void processFile(GFile file, File destFSFile, TaskMonitor monitor)
			throws IOException, CancelledException {
		if (!shouldSkip(file)) {
			super.processFile(file, destFSFile, monitor);
		}
	}

	@Override
	protected void processDirectory(GFile srcGFileDirectory, File destDirectory,
			TaskMonitor monitor) throws IOException, CancelledException {

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Select a genuine Ghidra project archive (.gar) created by ArchivePlugin, which is a zip.
  2. Re-create the archive from a valid project if the file is corrupt or mis-typed.
  3. If the FS protocol is reported incorrectly, inspect fs.getFSRL() and re-open the file through the zip filesystem layer.
  4. Catch IOException and present a clear 'not a project archive' message to the user.

Example fix

// before
private void verifyArchive(GFileSystem fs, TaskMonitor monitor) throws IOException {
    if (!fs.getFSRL().getProtocol().equals("zip")) {
        throw new IOException("Not a zip file: " + fs.getFSRL());
    }
    ...
}

// after — re-open via zip FS before rejecting, clearer error
private void verifyArchive(GFileSystem fs, TaskMonitor monitor) throws IOException {
    if (!fs.getFSRL().getProtocol().equals("zip")) {
        fs = FileSystemService.getInstance().openFileSystem(
            fs.getFSRL().withProtocol("zip"), monitor);
    }
    if (!fs.getFSRL().getProtocol().equals("zip")) {
        throw new IOException("Selected file is not a Ghidra project archive (.gar must be zip): " + fs.getFSRL());
    }
    ...
}
Defensive patterns

Strategy: validation

Validate before calling

if (!"zip".equals(fs.getFSRL().getProtocol())) {
    // re-open through the zip filesystem layer or reject with a clear message
    throw new IOException("Selected file is not a Ghidra project archive (must be zip): " + fs.getFSRL());
}

Type guard

boolean isZip = "zip".equals(fs.getFSRL().getProtocol());

Try / catch

try {
    verifyArchive(fs, monitor);
} catch (IOException e) {
    Msg.showError(this, null, "Restore Failed", "Not a project archive: " + e.getMessage());
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/09f9b82c1ea3f7ff. Report an issue: GitHub.