github/copilot-sdk · error · IOException

Published Copilot CLI is not a non-empty executable file:

Error message

Published Copilot CLI is not a non-empty executable file: 

What it means

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.

Solutions

  1. Check the cached CLI file on disk (size, permissions, ls -l) and delete it so the next run re-extracts it.
  2. Verify the CLI classpath resource in the artifact is intact (compare size/checksum with the official release).
  3. Exclude the cache directory from antivirus real-time scanning or move the cache dir.
  4. Ensure the cache directory is on a local filesystem that supports the executable bit (not FAT/network shares).

Example fix

// before
rm -rf ~/.cache/copilot  // stale/corrupt cached CLI persists
// after
rm -rf ~/.cache/copilot && mvn verify  // force re-extraction from a verified artifact
Defensive patterns

Strategy: fallback

Validate before calling

// Java: check the cached CLI before invoking the loader path
Path cli = Path.of(cacheDir.toString(), "copilot");
boolean ok = Files.isRegularFile(cli) && Files.size(cli) > 0 && Files.isExecutable(cli);
if (!ok) Files.deleteIfExists(cli); // force clean re-extraction

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/504e56ff352e3467. Report an issue: GitHub.

Appendix: source

Thrown at java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java:526

        URL cliResource = loader.getResource(cliResourcePath);
        if (cliResource == null) {
            // CLI not on classpath — this is allowed for the COPILOT_CLI_PATH fallback
            // path but will fail later in resolveEntrypoint() if InProcess is selected.
            return;
        }

        Files.createDirectories(cacheDir);
        Path temp = Files.createTempFile(cacheDir, "cli-tmp-", "");
        try {
            copyResourceToTemp(cliResource, cliResourcePath, temp);
            makeExecutable(temp);
            publisher.publish(temp, cachedCli);
        } finally {
            tryDelete(temp);
        }

        if (!isValidCachedCli(cachedCli)) {
            throw new IOException("Published Copilot CLI is not a non-empty executable file: " + cachedCli);
        }
    }

    /**
     * Tries source 2 (classpath extraction) first and falls back to source 3
     * (bundled-CLI sibling) only when the classpath resource is absent.
     */
    private static Path resolveFromClasspathOrBundledCli(Path cacheBase, ClassLoader loader, String classifier,
            String version, Path bundledCliDir, AtomicPublisher publisher) throws IOException {
        // Source 2: classpath resource.
        try {
            return extractToCache(cacheBase, loader, classifier, version, publisher);
        } catch (FileNotFoundException ex) {
            // Source 3: runtime.node alongside the bundled CLI binary.
            if (bundledCliDir != null) {
                Path candidate = bundledCliDir.resolve(RUNTIME_FILENAME);
                try {
                    if (isValidCachedFile(candidate)) {

View on GitHub (pinned to cd8cf15dc3)