skylot/jadx · error · RuntimeException

Failed to write metadata file

Error message

Failed to write metadata file

What it means

CodeMetadataAdapter.write serializes code metadata (line mappings and annotations) to a .jadxmd file using a DataOutputStream. If any IO or serialization error occurs during writing, it is wrapped in a RuntimeException. This is part of jadx-gui's disk code cache for faster subsequent decompilation.

Source

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

public class CodeMetadataAdapter {
	private static final byte[] JADX_METADATA_HEADER = "jadxmd".getBytes(StandardCharsets.US_ASCII);

	private final CodeAnnotationAdapter codeAnnotationAdapter;

	public CodeMetadataAdapter(RootNode root) {
		codeAnnotationAdapter = new CodeAnnotationAdapter(root);
	}

	public void write(Path metadataFile, ICodeMetadata metadata) {
		FileUtils.makeDirsForFile(metadataFile);
		try (OutputStream fileOutput = Files.newOutputStream(metadataFile, WRITE, CREATE, TRUNCATE_EXISTING);
				DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fileOutput))) {
			out.write(JADX_METADATA_HEADER);
			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);
		}
	}

View on GitHub (pinned to e738a26571)

Solutions

  1. Free disk space in the cache directory (typically under the user home or temp)
  2. Check permissions on the jadx cache directory
  3. Clear the jadx cache directory to reset state
  4. Reduce the number of classes or disable code caching in jadx settings

Example fix

// Clear the cache directory manually:
// Linux/Mac: rm -rf ~/.jadx/cache
// Or in jadx-gui: File > Clear Cache
// No API code fix needed — this is an internal cache write.
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure cache directory is writable and has space before starting
Path cacheDir = JadxFiles.CACHE_DIR;
Files.createDirectories(cacheDir);
if (!Files.isWritable(cacheDir)) { throw new IllegalStateException("Cache dir not writable"); }

Try / catch

// Internal to jadx-gui; no caller API. Clear cache on failure:
// catch is inside DiskCodeCache; user action is to clear the cache dir.

Prevention

When it happens

Trigger: write() opens the metadata file with CREATE+TRUNCATE_EXISTING, writes a header and line/annotation maps. Any exception (disk full, permission error, serialization failure) triggers the RuntimeException. Called by DiskCodeCache's async write pool during background caching.

Common situations: Disk full or quota exceeded in the cache directory. Permission issues in the user's cache directory. Concurrent file access or locking. Corrupted cache state from a previous interrupted write. JVM running out of memory during large annotation serialization.

Related errors


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