{"record":{"id":"a92f5afc04e2fbd9","repo":"spring-projects/spring-boot","slug":"failed-to-get-mode-from-filecopydetails","errorCode":null,"errorMessage":"Failed to get mode from FileCopyDetails","messagePattern":"Failed to get mode from FileCopyDetails","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java","lineNumber":485,"sourceCode":"\t\t\treturn (BootZipCopyAction.this.dirMode != null) ? BootZipCopyAction.this.dirMode : getPermissions(details);\n\t\t}\n\n\t\tprivate int getFileMode(FileCopyDetails details) {\n\t\t\treturn (BootZipCopyAction.this.fileMode != null) ? BootZipCopyAction.this.fileMode\n\t\t\t\t\t: getPermissions(details);\n\t\t}\n\n\t\tprivate int getPermissions(FileCopyDetails details) {\n\t\t\treturn (GradleVersion.current().compareTo(GradleVersion.version(\"8.3\")) >= 0)\n\t\t\t\t\t? details.getPermissions().toUnixNumeric() : getMode(details);\n\t\t}\n\n\t\tprivate int getMode(FileCopyDetails details) {\n\t\t\ttry {\n\t\t\t\treturn (int) details.getClass().getMethod(\"getMode\").invoke(details);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException(\"Failed to get mode from FileCopyDetails\", ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * Callback interface used to customize a {@link ZipArchiveEntry}.\n\t */\n\t@FunctionalInterface\n\tprivate interface ZipEntryCustomizer {\n\n\t\tZipEntryCustomizer NONE = (entry) -> {\n\t\t};\n\n\t\t/**\n\t\t * Customize the entry.\n\t\t * @param entry the entry to customize\n\t\t * @throws IOException on IO error","sourceCodeStart":467,"sourceCodeEnd":503,"githubUrl":"https://github.com/spring-projects/spring-boot/blob/270dfe353fb830fd69b823a8a859287ff103854b/build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java#L467-L503","documentation":"Thrown by BootZipCopyAction's getMode, which reflectively invokes FileCopyDetails.getMode() on the legacy path for Gradude versions below 8.3 (the caller checks GradleVersion 8.3 and uses details.getPermissions().toUnixNumeric() on modern Gradle, falling back to getMode otherwise). Any reflection exception — NoSuchMethodException, IllegalAccessException, InvocationTargetException — is wrapped in a RuntimeException.","triggerScenarios":"Building a boot archive on Gradle < 8.3 where FileCopyDetails lacks a getMode() method or the method throws during invocation. The modern path (details.getPermissions().toUnixNumeric()) is only taken on 8.3+.","commonSituations":"Running on an old Gradle version (< 8.3). A custom FileCopyDetails implementation that hides getMode(). Co-occurs with errors [5] and [6] as part of the same legacy-permissions reflection cluster.","solutions":["Upgrade Gradle to 8.3+ so the modern getPermissions().toUnixNumeric() path is used.","Remove any plugin that replaces FileCopyDetails implementations.","If pinned to old Gradle, downgrade the Spring Boot plugin to a compatible version."],"exampleFix":"// before: Gradle 7.x uses reflective getMode\n// after: upgrade wrapper\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.14.2-bin.zip","handlingStrategy":"validation","validationCode":"// Gate on Gradle 8.3+ to use the modern permissions API.\nif (GradleVersion.current().compareTo(GradleVersion.version(\"8.3\")) < 0) {\n    throw new GradleException(\"Upgrade to Gradle 8.3+ to avoid reflective getMode.\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use Gradle 8.3+ (preferably 8.14+) via the wrapper.","Do not replace FileCopyDetails with custom implementations.","Keep Gradle and Spring Boot plugin versions aligned."],"tags":["gradle","reflection","file-permissions","version-compat","boot-archive","zip"],"backgroundTag":null,"analyzedSha":"270dfe353fb830fd69b823a8a859287ff103854b","analyzedAt":"2026-08-11T19:42:06.541Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}