skylot/jadx · error · JadxRuntimeException

Failed to build hash for inputs

Error message

Failed to build hash for inputs

What it means

Thrown by buildInputsHash(List<Path>) which computes an MD5 over the sorted input files' modification timestamps. The method expands directories, sorts, reads Files.getLastModifiedTime for each file, and writes timestamps to a DataOutputStream. Failure means: a file in the expanded list does not exist when getLastModifiedTime is called (NoSuchFileException — a race if files are deleted during hashing), an I/O error reading timestamps, or expandDirs encountered an inaccessible path.

Source

Thrown at jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java:521

	}

	/**
	 * Hash timestamps of input files
	 */
	public static String buildInputsHash(List<Path> inputPaths) {
		try (ByteArrayOutputStream bout = new ByteArrayOutputStream();
				DataOutputStream data = new DataOutputStream(bout)) {
			List<Path> inputFiles = FileUtils.expandDirs(inputPaths);
			Collections.sort(inputFiles);
			data.write(inputPaths.size());
			data.write(inputFiles.size());
			for (Path inputFile : inputFiles) {
				FileTime modifiedTime = Files.getLastModifiedTime(inputFile);
				data.writeLong(modifiedTime.toMillis());
			}
			return FileUtils.md5Sum(bout.toByteArray());
		} catch (Exception e) {
			throw new JadxRuntimeException("Failed to build hash for inputs", e);
		}
	}
}

View on GitHub (pinned to e738a26571)

Solutions

  1. Ensure input files are stable (not being concurrently modified/deleted) during the hash call.
  2. Pre-validate that all expanded input files exist: inputFiles.forEach(p -> { if (!Files.exists(p)) throw ... }).
  3. Filter out broken symlinks before hashing: Files.exists(path) and !Files.isSymbolicLink(path) or resolve links first.
  4. Copy inputs to a stable local directory before hashing in CI.

Example fix

// before
String hash = FileUtils.buildInputsHash(inputs);

// after — pre-validate existence
List<Path> expanded = FileUtils.expandDirs(inputs);
for (Path p : expanded) {
    if (!Files.exists(p)) throw new IllegalStateException("input vanished: " + p);
}
String hash = FileUtils.buildInputsHash(inputs);
Defensive patterns

Strategy: validation

Validate before calling

public static boolean allInputsExist(List<Path> inputs) {
    for (Path p : FileUtils.expandDirs(inputs)) {
        if (!Files.exists(p)) return false;
    }
    return true;
}

Try / catch

try {
    String hash = FileUtils.buildInputsHash(inputs);
} catch (JadxRuntimeException e) {
    Throwable cause = e.getCause();
    if (cause instanceof NoSuchFileException) {
        LOG.warn("input file vanished during hashing: {}", cause.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling buildInputsHash while input files are being modified or deleted concurrently (TOCTOU race). An input path that is a broken symlink. A directory in the input list that becomes unreadable during expansion. Files on a network share that disconnects mid-hash.

Common situations: CI pipelines that clean up build artifacts while jadx is still hashing. Concurrent decompilation processes sharing the same input directory. Network-mounted input that disconnects. Broken symlinks in the input tree pointing to removed targets.

Related errors


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