skylot/jadx · error · RuntimeException

Failed to parse code annotations

Error message

Failed to parse code annotations

What it means

CodeMetadataAdapter.readAndBuild reads a cached .jadxmd file to reconstruct code annotations. If the file is corrupted, truncated, or written by an incompatible jadx version, deserialization fails and a RuntimeException is thrown. This only triggers when a pre-existing cache file exists.

Source

Thrown at jadx-gui/src/main/java/jadx/gui/cache/code/disk/CodeMetadataAdapter.java:65

			writeLines(out, metadata.getLineMapping());
			writeAnnotations(out, metadata.getAsMap());
		} catch (Exception e) {
			throw new RuntimeException("Failed to write metadata file", e);
		}
	}

	public ICodeInfo readAndBuild(Path metadataFile, String code) {
		if (!Files.exists(metadataFile)) {
			return new SimpleCodeInfo(code);
		}
		try (InputStream fileInput = Files.newInputStream(metadataFile);
				DataInputStream in = new DataInputStream(new BufferedInputStream(fileInput))) {
			in.skipBytes(JADX_METADATA_HEADER.length);
			Map<Integer, Integer> lines = readLines(in);
			Map<Integer, ICodeAnnotation> annotations = readAnnotations(in);
			return new AnnotatedCodeInfo(code, lines, annotations);
		} catch (Exception e) {
			throw new RuntimeException("Failed to parse code annotations", e);
		}
	}

	private void writeLines(DataOutput out, Map<Integer, Integer> lines) throws IOException {
		out.writeInt(lines.size());
		for (Map.Entry<Integer, Integer> entry : lines.entrySet()) {
			DataAdapterHelper.writeUVInt(out, entry.getKey());
			DataAdapterHelper.writeUVInt(out, entry.getValue());
		}
	}

	private Map<Integer, Integer> readLines(DataInput in) throws IOException {
		int size = in.readInt();
		if (size == 0) {
			return Collections.emptyMap();
		}
		Map<Integer, Integer> lines = new HashMap<>(size);
		for (int i = 0; i < size; i++) {

View on GitHub (pinned to e738a26571)

Solutions

  1. Clear the jadx cache directory to force a fresh decompilation
  2. Upgrade jadx — cache format version checks may have been added
  3. Ensure the cache directory is not shared across jadx versions
  4. Disable disk caching if the problem recurs

Example fix

// Clear cache to resolve format corruption:
// rm -rf ~/.cache/jadx  (or the configured cache dir)
// Or set a fresh cache location in jadx-gui settings.
Defensive patterns

Strategy: fallback

Validate before calling

// Clear cache before loading if version changed
Path metaFile = cacheDir.resolve(clsId + ".jadxmd");
if (isIncompatibleVersion(metaFile)) { Files.deleteIfExists(metaFile); }

Try / catch

// This is internal; the catch in readAndBuild rethrows. User remedy:
// delete the cache directory to force fresh decompilation.

Prevention

When it happens

Trigger: readAndBuild opens the metadata file, skips the header, reads line mappings and annotations via DataInputStream. Any exception (EOFException, malformed UVInt, negative array size, version mismatch) is caught and wrapped. Called when loading a previously cached class from disk.

Common situations: Cache written by an older or newer jadx version with a different format. Cache file truncated by a crash or disk-full during a previous write. Cache directory modified or partially deleted by external processes. OS or antivirus corrupting cache files.

Understand the failure class

Related errors


AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14). Data as JSON: /api/errors/9275d4390f2a19de. Report an issue: GitHub.