{"record":{"id":"1d4870c55aed76ed","repo":"quarkusio/quarkus","slug":"failed-to-hash-content-of","errorCode":null,"errorMessage":"Failed to hash content of ","messagePattern":"Failed to hash content of ","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/ToolingUtils.java","lineNumber":283,"sourceCode":"            return cached.hash();\n        }\n        final String hash = sha1(file);\n        DIGEST_CACHE.put(f.getAbsolutePath(), new FileDigest(lastModified, length, hash));\n        return hash;\n    }\n\n    /**\n     * Computes the hex-encoded SHA-1 of a file's content, streaming it without loading it into memory.\n     */\n    private static String sha1(Path file) {\n        final MessageDigest digest = sha1Digest();\n        try (InputStream in = Files.newInputStream(file)) {\n            final byte[] buffer = new byte[8192];\n            for (int read = in.read(buffer); read >= 0; read = in.read(buffer)) {\n                digest.update(buffer, 0, read);\n            }\n        } catch (IOException e) {\n            throw new UncheckedIOException(\"Failed to hash content of \" + file, e);\n        }\n        return HexFormat.of().formatHex(digest.digest());\n    }\n\n    private static MessageDigest sha1Digest() {\n        try {\n            return MessageDigest.getInstance(\"SHA-1\");\n        } catch (NoSuchAlgorithmException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n}\n","sourceCodeStart":265,"sourceCodeEnd":296,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/ToolingUtils.java#L265-L296","documentation":"ToolingUtils.sha1() streams a file through a SHA-1 MessageDigest to fingerprint local artifacts (with caching by path/mtime/size). If reading the file throws an IOException — file deleted between the exists() check and open, permission denied, or a filesystem/IO error — the IOException is wrapped in an UncheckedIOException so callers that handle only Unchecked exceptions are not forced to catch IOException. The message includes the file path being hashed.","triggerScenarios":"Calling ToolingUtils.hash(file) (via sha1) on a file that disappears mid-build (concurrent clean), on a file without read permission, or when the underlying filesystem fails during streaming (e.g. network mount dropped).","commonSituations":"Gradle daemon builds where a clean task or another process deletes a dependency JAR while Quarkus tooling hashes it; read-protected files under a user cache directory; NFS/overlayfs transient IO errors in CI containers.","solutions":["Re-run the build — transient IO errors or races with a concurrent clean usually resolve on retry","Verify the file exists and is readable by the Gradle daemon user (ls -l, check permissions/ACLs)","Check the cause chain (e.getCause()) to distinguish FileNotFoundException (deleted/moved) from AccessDeniedException (permissions)","Exclude conflicting concurrent tasks (clean running alongside quarkus tooling) or disable build caches that prune files mid-build","Check disk/filesystem health if the error persists on different files"],"exampleFix":"// before (no guard)\nString hash = ToolingUtils.hash(path);\n// after (caller-side guard)\nif (!Files.isReadable(path)) {\n    throw new IllegalStateException(\"Cannot read artifact for hashing: \" + path);\n}\ntry {\n    String hash = ToolingUtils.hash(path);\n} catch (UncheckedIOException e) {\n    if (e.getCause() instanceof NoSuchFileException) {\n        hash = ToolingUtils.hash(path); // re-created after concurrent clean\n    } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"if (!Files.isReadable(file)) {\n    throw new IllegalStateException(\"Cannot hash unreadable file: \" + file);\n}\ntry (var in = Files.newInputStream(file)) { /* probe open */ }","typeGuard":null,"tryCatchPattern":"try {\n    String hash = ToolingUtils.hash(file);\n} catch (UncheckedIOException e) {\n    if (e.getCause() instanceof NoSuchFileException || e.getCause() instanceof AccessDeniedException) {\n        // recover: re-check existence/permissions and retry once\n    } else throw new RuntimeException(\"Hashing failed for \" + file, e);\n}","preventionTips":["Verify file readability before hashing","Avoid running clean tasks concurrently with Quarkus tooling tasks","Watch the cause chain: NoSuchFileException vs AccessDeniedException point to different fixes","Keep artifact caches on healthy local filesystems, not flaky network mounts"],"tags":["gradle","io","file-read","sha1"],"backgroundTag":"file-read-failed","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}