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
- 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).
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
- 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
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
- Filesystem does not support atomic moves; cannot safely…
- Unsafe runtime asset inventory path:
- Runtime asset escapes cache directory:
- Runtime asset not found on classpath:
- Failed to make Copilot CLI executable:
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)