{"record":{"id":"5352ffc9b6e5ed5a","repo":"skylot/jadx","slug":"failed-to-build-hash-for-inputs","errorCode":null,"errorMessage":"Failed to build hash for inputs","messagePattern":"Failed to build hash for inputs","errorType":"exception","errorClass":"JadxRuntimeException","httpStatus":null,"severity":"error","filePath":"jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java","lineNumber":521,"sourceCode":"\t}\n\n\t/**\n\t * Hash timestamps of input files\n\t */\n\tpublic static String buildInputsHash(List<Path> inputPaths) {\n\t\ttry (ByteArrayOutputStream bout = new ByteArrayOutputStream();\n\t\t\t\tDataOutputStream data = new DataOutputStream(bout)) {\n\t\t\tList<Path> inputFiles = FileUtils.expandDirs(inputPaths);\n\t\t\tCollections.sort(inputFiles);\n\t\t\tdata.write(inputPaths.size());\n\t\t\tdata.write(inputFiles.size());\n\t\t\tfor (Path inputFile : inputFiles) {\n\t\t\t\tFileTime modifiedTime = Files.getLastModifiedTime(inputFile);\n\t\t\t\tdata.writeLong(modifiedTime.toMillis());\n\t\t\t}\n\t\t\treturn FileUtils.md5Sum(bout.toByteArray());\n\t\t} catch (Exception e) {\n\t\t\tthrow new JadxRuntimeException(\"Failed to build hash for inputs\", e);\n\t\t}\n\t}\n}\n","sourceCodeStart":503,"sourceCodeEnd":525,"githubUrl":"https://github.com/skylot/jadx/blob/e738a26571d02919f01df40de93bc9a44dee4e18/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java#L503-L525","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure input files are stable (not being concurrently modified/deleted) during the hash call.","Pre-validate that all expanded input files exist: inputFiles.forEach(p -> { if (!Files.exists(p)) throw ... }).","Filter out broken symlinks before hashing: Files.exists(path) and !Files.isSymbolicLink(path) or resolve links first.","Copy inputs to a stable local directory before hashing in CI."],"exampleFix":"// before\nString hash = FileUtils.buildInputsHash(inputs);\n\n// after — pre-validate existence\nList<Path> expanded = FileUtils.expandDirs(inputs);\nfor (Path p : expanded) {\n    if (!Files.exists(p)) throw new IllegalStateException(\"input vanished: \" + p);\n}\nString hash = FileUtils.buildInputsHash(inputs);","handlingStrategy":"validation","validationCode":"public static boolean allInputsExist(List<Path> inputs) {\n    for (Path p : FileUtils.expandDirs(inputs)) {\n        if (!Files.exists(p)) return false;\n    }\n    return true;\n}","typeGuard":null,"tryCatchPattern":"try {\n    String hash = FileUtils.buildInputsHash(inputs);\n} catch (JadxRuntimeException e) {\n    Throwable cause = e.getCause();\n    if (cause instanceof NoSuchFileException) {\n        LOG.warn(\"input file vanished during hashing: {}\", cause.getMessage());\n    }\n    throw e;\n}","preventionTips":["Ensure input files are stable (not concurrently modified/deleted) during hashing.","Pre-validate that all expanded input files exist.","Copy inputs to a stable local directory before hashing in concurrent CI."],"tags":["hash","file-io","race-condition","cache-key","jadx"],"backgroundTag":null,"analyzedSha":"e738a26571d02919f01df40de93bc9a44dee4e18","analyzedAt":"2026-08-14T00:10:24.238Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}