github/copilot-sdk · error · IOException
Published runtime wrapper is not a non-empty executable…
Error message
Published runtime wrapper is not a non-empty executable file:
What it means
After copying the runtime wrapper to a temp file and atomically publishing it into the cache, the loader re-validates the published file (non-empty, regular, executable) and it fails. This indicates the publish produced a corrupt or unusable file rather than a clean extraction.
Solutions
- Clear the runtime cache (rm -rf ~/.copilot/runtime-cache) and retry resolution.
- Ensure the cache directory is on a local filesystem that supports atomic moves and POSIX permissions (avoid NFS homes).
- Run only one instance at a time or serialize first startup; then restart to re-extract.
- Check that no antivirus/cleanup daemon is deleting or chmod'ing files under ~/.copilot/runtime-cache.
Example fix
// before
Path wrapper = NativeRuntimeLoader.resolveRuntimeWrapper();
// after: validate cache and clear it if the wrapper is unusable
Path wrapper;
try {
wrapper = NativeRuntimeLoader.resolveRuntimeWrapper();
} catch (IOException e) {
Files.walkFileTree(Path.of(System.getProperty("user.home"), ".copilot", "runtime-cache"),
new SimpleFileVisitor<>() { public FileVisitResult visitFile(Path f, BasicFileAttributes a) throws IOException { Files.delete(f); return FileVisitResult.CONTINUE; } });
wrapper = NativeRuntimeLoader.resolveRuntimeWrapper();
} Defensive patterns
Strategy: retry
Validate before calling
Path wrapper = Path.of(System.getProperty("user.home"), ".copilot", "runtime-cache")
// walk to wrapper once resolved; precheck: existing wrapper must be non-empty and executable
boolean ok = Files.isRegularFile(p) && Files.size(p) > 0 && (isWindows() || Files.isExecutable(p));
Try / catch
try {
Path wrapper = NativeRuntimeLoader.resolveRuntimeWrapper();
} catch (IOException e) {
if (e.getMessage().startsWith("Published runtime wrapper")) {
deleteRuntimeCache();
wrapper = NativeRuntimeLoader.resolveRuntimeWrapper();
} else throw e;
} Prevention
- Keep ~/.copilot/runtime-cache on a local, POSIX-capable filesystem.
- Don't run multiple instances on a cold shared cache concurrently.
- Exclude the cache directory from antivirus/cleanup jobs.
- Monitor disk space and permissions in the home directory.
When it happens
Trigger: A concurrent publisher replaced cachedWrapper with a truncated/empty file between publish and validation; the cache directory filesystem doesn't preserve the executable bit; disk-full or permission issue corrupted the moved file.
Common situations: Shared NFS/network home directories without reliable atomic move semantics; concurrent app instances racing on ~/.copilot/runtime-cache; security software stripping the execute bit after extraction; read-only or quota-exceeded cache directory.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Concurrent extraction race: target already exists but is…
- Failed to make Copilot CLI executable:
- failed to chmod binary
- creating install directory
- creating runtime asset directory
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/0940b1c8766f6362.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java:215
}
String resourcePath = "native/" + classifier + "/" + wrapperName;
URL resource = loader.getResource(resourcePath);
if (resource == null) {
throw new FileNotFoundException("Runtime wrapper not found on classpath: " + resourcePath
+ " — add the matching classifier JAR to the classpath");
}
Path temp = Files.createTempFile(cacheDir, "runtime-wrapper-tmp-", "");
try {
copyResourceToTemp(resource, resourcePath, temp);
makeExecutable(temp);
DEFAULT_PUBLISHER.publish(temp, cachedWrapper);
} finally {
tryDelete(temp);
}
if (!isValidCachedCli(cachedWrapper)) {
throw new IOException("Published runtime wrapper is not a non-empty executable file: " + cachedWrapper);
}
return cachedWrapper;
}
static Path resolveEntrypoint(String configuredCli, Path runtimePath) throws IOException {
if (configuredCli != null && !configuredCli.isBlank()) {
Path configuredPath = Path.of(configuredCli).toAbsolutePath().normalize();
if (resolveFromCliPath(configuredCli) != null && Files.isRegularFile(configuredPath)
&& Files.size(configuredPath) > 0) {
return configuredPath;
}
}
Path parent = runtimePath.getParent();
String cliName = isWindows() ? CLI_FILENAME_WINDOWS : CLI_FILENAME;
Path cliPath = parent.resolve(cliName);
if (Files.isRegularFile(cliPath) && Files.size(cliPath) > 0) {
return cliPath;View on GitHub (pinned to cd8cf15dc3)