github/copilot-sdk · error · IOException

Copilot CLI executable not found at — the classifier JAR…

Error message

Copilot CLI executable not found at  — the classifier JAR must contain both runtime.node and the copilot binary

What it means

resolveEntrypoint() located the extracted runtime.node but could not find a non-empty copilot (copilot.exe on Windows) executable in the same directory. The classifier JAR is expected to bundle both the native runtime and the legacy CLI entrypoint; only the runtime was found.

Solutions

  1. Upgrade the platform classifier JAR to the same version as the SDK so it bundles both runtime.node and the copilot binary.
  2. Verify the JAR contents: jar tf copilot-sdk-native-*.jar | grep 'copilot$' (or copilot.exe).
  3. Set COPILOT_CLI_PATH to an explicitly installed copilot CLI that has a compatible runtime.node adjacent (flat layout or prebuilds/<classifier>).
  4. If you don't need legacy entrypoint hosting, avoid calling resolveEntrypoint() and use the standard runtime path.

Example fix

// before: mismatched native jar
<dependency>
  <artifactId>copilot-sdk-native</artifactId>
  <version>1.0.0</version>
  <classifier>linux-x64</classifier>
</dependency>

// after: align versions so copilot binary is bundled
<dependency>
  <artifactId>copilot-sdk-native</artifactId>
  <version>1.2.0</version>
  <classifier>linux-x64</classifier>
</dependency>
Defensive patterns

Strategy: fallback

Validate before calling

String cli = System.getenv("COPILOT_CLI_PATH");
boolean usable = cli != null && Files.isRegularFile(Path.of(cli)) && Files.size(Path.of(cli)) > 0;
if (!usable) {
    // ensure classifier JAR bundles the CLI before requesting the entrypoint
    boolean bundled = getClass().getResourceAsStream("/native/linux-x64/copilot") != null;
}

Try / catch

Path entrypoint;
try {
    entrypoint = NativeRuntimeLoader.resolveEntrypoint();
} catch (IOException e) {
    if (e.getMessage().startsWith("Copilot CLI executable not found")) {
        entrypoint = installOrLocateStandaloneCopilot(); // e.g. npm install path
    } else throw e;
}

Prevention

When it happens

Trigger: Calling NativeRuntimeLoader.resolveEntrypoint() (directly or via the SDK) with a classifier JAR that contains native/<classifier>/runtime.node but not native/<classifier>/copilot; or COPILOT_CLI_PATH pointing at a CLI without an adjacent valid runtime, then falling back to the cache dir which lacks the CLI.

Common situations: Classifier JAR version mismatch with the SDK (older JAR predates CLI bundling); slimmed-down native artifact; COPILOT_CLI_PATH pointing to a copy of the binary without siblings; legacy extension hosting requested on a platform JAR that never shipped the CLI.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

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

        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;
        }
        throw new IOException("Copilot CLI executable not found at " + cliPath
                + " — the classifier JAR must contain both runtime.node and the copilot binary");
    }

    /**
     * Reads the SDK version from the filtered {@code copilot-runtime.properties}
     * resource.
     *
     * @return the version string
     * @throws IOException
     *             if the resource cannot be read
     * @throws IllegalStateException
     *             if the resource is missing or the version property is blank
     */
    static String readVersion(ClassLoader loader) throws IOException {
        URL resource = loader.getResource(VERSION_RESOURCE);
        if (resource == null) {
            throw new IllegalStateException("Missing version resource: " + VERSION_RESOURCE
                    + " — ensure Maven resource filtering has run (mvn process-resources)");

View on GitHub (pinned to cd8cf15dc3)