{"record":{"id":"504e56ff352e3467","repo":"github/copilot-sdk","slug":"published-copilot-cli-is-not-a-non-empty-executabl","errorCode":null,"errorMessage":"Published Copilot CLI is not a non-empty executable file: ","messagePattern":"Published Copilot CLI is not a non-empty executable file: ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java","lineNumber":526,"sourceCode":"        URL cliResource = loader.getResource(cliResourcePath);\n        if (cliResource == null) {\n            // CLI not on classpath — this is allowed for the COPILOT_CLI_PATH fallback\n            // path but will fail later in resolveEntrypoint() if InProcess is selected.\n            return;\n        }\n\n        Files.createDirectories(cacheDir);\n        Path temp = Files.createTempFile(cacheDir, \"cli-tmp-\", \"\");\n        try {\n            copyResourceToTemp(cliResource, cliResourcePath, temp);\n            makeExecutable(temp);\n            publisher.publish(temp, cachedCli);\n        } finally {\n            tryDelete(temp);\n        }\n\n        if (!isValidCachedCli(cachedCli)) {\n            throw new IOException(\"Published Copilot CLI is not a non-empty executable file: \" + cachedCli);\n        }\n    }\n\n    /**\n     * Tries source 2 (classpath extraction) first and falls back to source 3\n     * (bundled-CLI sibling) only when the classpath resource is absent.\n     */\n    private static Path resolveFromClasspathOrBundledCli(Path cacheBase, ClassLoader loader, String classifier,\n            String version, Path bundledCliDir, AtomicPublisher publisher) throws IOException {\n        // Source 2: classpath resource.\n        try {\n            return extractToCache(cacheBase, loader, classifier, version, publisher);\n        } catch (FileNotFoundException ex) {\n            // Source 3: runtime.node alongside the bundled CLI binary.\n            if (bundledCliDir != null) {\n                Path candidate = bundledCliDir.resolve(RUNTIME_FILENAME);\n                try {\n                    if (isValidCachedFile(candidate)) {","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java#L508-L544","documentation":"extractCliToCache extracts the Copilot CLI executable from the classpath (or a bundled sibling) into the cache directory via an atomic publish, then validates the result with isValidCachedCli (non-empty, regular file, executable). If validation fails after publishing, this IOException is thrown — the CLI binary landed on disk but is unusable.","triggerScenarios":"After publisher.publish(temp, cachedCli), the cached CLI is zero bytes, not a regular file, or lacks the execute bit — e.g. the classpath resource itself was empty, an antivirus quarantined/modified the file, or the filesystem stripped the executable bit.","commonSituations":"Corrupted or stubbed CLI resource in the artifact; Windows Defender/enterprise AV deleting the freshly extracted binary; publishing to a filesystem (some network mounts, FAT) that doesn't preserve the exec bit; disk-full partially truncating the file.","solutions":["Check the cached CLI file on disk (size, permissions, ls -l) and delete it so the next run re-extracts it.","Verify the CLI classpath resource in the artifact is intact (compare size/checksum with the official release).","Exclude the cache directory from antivirus real-time scanning or move the cache dir.","Ensure the cache directory is on a local filesystem that supports the executable bit (not FAT/network shares)."],"exampleFix":"// before\nrm -rf ~/.cache/copilot  // stale/corrupt cached CLI persists\n// after\nrm -rf ~/.cache/copilot && mvn verify  // force re-extraction from a verified artifact","handlingStrategy":"fallback","validationCode":"// Java: check the cached CLI before invoking the loader path\nPath cli = Path.of(cacheDir.toString(), \"copilot\");\nboolean ok = Files.isRegularFile(cli) && Files.size(cli) > 0 && Files.isExecutable(cli);\nif (!ok) Files.deleteIfExists(cli); // force clean re-extraction","typeGuard":null,"tryCatchPattern":"try { loader.extractCliToCache(...); } catch (IOException e) { if (e.getMessage().startsWith(\"Published Copilot CLI is not a non-empty executable file\")) { Files.deleteIfExists(cachedCli); /* retry once from a verified artifact */ } else throw e; }","preventionTips":["Whitelist the cache directory in antivirus software","Place the cache on a local filesystem that preserves the executable bit","Monitor disk space; partial writes on full disks corrupt binaries","Delete stale cache dirs after upgrading library versions"],"tags":["filesystem","executable","java","native-assets"],"backgroundTag":"file-write-failed","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}