{"record":{"id":"23b2812916ace418","repo":"apache/flink","slug":"the-discovery-script-s-is-not-executable","errorCode":null,"errorMessage":"The discovery script %s is not executable.","messagePattern":"The discovery script (.+?) is not executable\\.","errorType":"exception","errorClass":"FlinkException","httpStatus":null,"severity":"error","filePath":"flink-external-resources/flink-external-resource-gpu/src/main/java/org/apache/flink/externalresource/gpu/GPUDriver.java","lineNumber":89,"sourceCode":"        }\n\n        Path discoveryScriptPath = Paths.get(discoveryScriptPathStr);\n        if (!discoveryScriptPath.isAbsolute()) {\n            discoveryScriptPath =\n                    Paths.get(\n                            System.getenv().getOrDefault(ConfigConstants.ENV_FLINK_HOME_DIR, \".\"),\n                            discoveryScriptPathStr);\n        }\n        discoveryScriptFile = discoveryScriptPath.toFile();\n\n        if (!discoveryScriptFile.exists()) {\n            throw new FileNotFoundException(\n                    String.format(\n                            \"The gpu discovery script does not exist in path %s.\",\n                            discoveryScriptFile.getAbsolutePath()));\n        }\n        if (!discoveryScriptFile.canExecute()) {\n            throw new FlinkException(\n                    String.format(\n                            \"The discovery script %s is not executable.\",\n                            discoveryScriptFile.getAbsolutePath()));\n        }\n\n        args = config.get(DISCOVERY_SCRIPT_ARG);\n    }\n\n    @Override\n    public Set<GPUInfo> retrieveResourceInfo(long gpuAmount) throws Exception {\n        Preconditions.checkArgument(\n                gpuAmount > 0,\n                \"The gpuAmount should be positive when retrieving the GPU resource information.\");\n\n        final Set<GPUInfo> gpuResources = new HashSet<>();\n        String output = executeDiscoveryScript(discoveryScriptFile, gpuAmount, args);\n        if (!output.isEmpty()) {\n            String[] indexes = output.split(\",\");","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-external-resources/flink-external-resource-gpu/src/main/java/org/apache/flink/externalresource/gpu/GPUDriver.java#L71-L107","documentation":"Thrown by GPUDriver when the GPU discovery script file exists but the JVM sees it as non-executable (File.canExecute() == false). This is a filesystem permission check done after the existence check in the constructor, so it only fires once the path itself is correct.","triggerScenarios":"Constructing GPUDriver with a discovery script whose execute bit is not set for the user running the TaskManager JVM: chmod missing, file copied without preserving permissions, or a read-only mount (some Docker volumes, ConfigMaps in Kubernetes) that drops the +x bit.","commonSituations":"Kubernetes ConfigMap volumes mount files as 0644 by default; extracting a tarball as root and running Flink as another user; scripts edited/re-uploaded via a tool that resets permissions.","solutions":["Run 'chmod +x <script>' on every TaskManager node (see the absolute path in the error message)","For Kubernetes ConfigMaps, set defaultMode to 0755 on the volume mount","Copy files with 'cp -p' or 'rsync -p' / extract with 'tar -p' to preserve the execute bit","Verify with 'sudo -u <flink-user> test -x <script> && echo ok'"],"exampleFix":"# before\n$ ls -l /opt/flink/scripts/gpu-discovery.sh\n-rw-r--r-- 1 flink flink 512 ...\n\n# after\n$ chmod +x /opt/flink/scripts/gpu-discovery.sh\n$ ls -l /opt/flink/scripts/gpu-discovery.sh\n-rwxr-xr-x 1 flink flink 512 ...","handlingStrategy":"validation","validationCode":"java.io.File f = new java.io.File(scriptPath);\nif (f.exists() && !f.canExecute()) {\n    throw new IllegalStateException(\"Make the GPU discovery script executable: chmod +x \" + f.getAbsolutePath());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run chmod +x in the Dockerfile after copying scripts","Set defaultMode: 0755 on Kubernetes ConfigMap volume mounts","Include a permissions smoke test in the container entrypoint"],"tags":["gpu","external-resources","permissions","configuration"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}