github/copilot-sdk · error · IOException

Invalid runtime asset inventory entry:

Error message

Invalid runtime asset inventory entry: 

What it means

A line in the runtime-assets.list inventory resource did not split into exactly two tab-separated fields (octal mode and relative path). The loader treats the inventory as a strict manifest for extracting extra runtime assets, so a malformed line aborts extraction to avoid silently skipping assets.

Solutions

  1. Replace the classifier JAR with an official release artifact whose runtime-assets.list is well-formed (mode<TAB>path per line).
  2. Inspect the manifest: unzip -p copilot-sdk-native-*.jar native/<classifier>/runtime-assets.list and check each line has exactly one tab.
  3. If building the JAR yourself, fix the manifest generation step to emit tab-separated mode and path fields.
  4. Purge the cached/local Maven copy and re-download to rule out artifact corruption.

Example fix

// before: runtime-assets.list (malformed)
0755 assets/node_modules/module.js
 0755  extra/tool

// after (mode<TAB>relative path, one per line)
0755	assets/node_modules/module.js
0755	extra/tool
Defensive patterns

Strategy: validation

Validate before calling

try (BufferedReader r = new BufferedReader(new InputStreamReader(
        getClass().getResourceAsStream("/native/" + classifier + "/runtime-assets.list"), UTF_8))) {
    String line;
    while ((line = r.readLine()) != null)
        if (!line.isBlank() && line.split("\t", -1).length < 2)
            throw new IllegalStateException("Malformed runtime-assets.list entry: " + line);
}

Try / catch

try {
    Path runtime = NativeRuntimeLoader.resolve();
} catch (IOException e) {
    if (e.getMessage().startsWith("Invalid runtime asset inventory entry")) {
        throw new IllegalStateException("Classifier JAR manifest is corrupt; replace with an official artifact", e);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling resolve()/extractToCache() with a classifier JAR whose runtime-assets.list is corrupted, hand-edited, line-wrapped by a text editor, or uses spaces/newlines instead of tabs as separators.

Common situations: Locally regenerated classifier JARs where the manifest was written with spaces or CRLF-joined fields; a build step that re-formatted or minified resource files; truncated download of the classifier artifact.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

    private static void extractRuntimeAssetsToCache(Path cacheDir, ClassLoader loader, String classifier,
            AtomicPublisher publisher) throws IOException {
        String inventoryResourcePath = "native/" + classifier + "/" + RUNTIME_ASSETS_FILENAME;
        URL inventoryResource = loader.getResource(inventoryResourcePath);
        if (inventoryResource == null) {
            return;
        }

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(inventoryResource.openStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.isBlank()) {
                    continue;
                }
                String[] fields = line.split("\\t", 2);
                if (fields.length != 2) {
                    throw new IOException("Invalid runtime asset inventory entry: " + line);
                }
                boolean executable = (Integer.parseInt(fields[0], 8) & 0111) != 0;
                Path relative = Path.of(fields[1]).normalize();
                if (relative.isAbsolute() || relative.startsWith("..")) {
                    throw new IOException("Unsafe runtime asset inventory path: " + fields[1]);
                }
                Path cached = cacheDir.resolve(relative).normalize();
                if (!cached.startsWith(cacheDir)) {
                    throw new IOException("Runtime asset escapes cache directory: " + fields[1]);
                }
                if (isValidCachedFile(cached) && (!executable || isWindows() || Files.isExecutable(cached))) {
                    continue;
                }

                String resourcePath = "native/" + classifier + "/" + fields[1];
                URL resource = loader.getResource(resourcePath);
                if (resource == null) {
                    throw new FileNotFoundException("Runtime asset not found on classpath: " + resourcePath);

View on GitHub (pinned to cd8cf15dc3)