conductor-oss/conductor · error · IllegalArgumentException

Skill package contains duplicate path: {path}

Error message

Skill package contains duplicate path: {path}

What it means

Thrown by parseSkillPackage when two zip entries normalize to the same path. normalizeEntryName converts backslashes to slashes and strips leading './', so entries like 'foo/./bar' and 'foo/bar', or 'a\\b' and 'a/b', collide. This is a package integrity check preventing ambiguous content.

Source

Thrown at agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java:442

    @SuppressWarnings("unchecked")
    private ParsedSkillPackage parseSkillPackage(byte[] bytes, Map<String, Object> manifest) {
        List<SkillFileEntry> files = new ArrayList<>();
        Map<String, byte[]> contentByPath = new TreeMap<>();
        long totalUncompressedBytes = 0;
        try (ZipInputStream zip = new ZipInputStream(new ByteArrayInputStream(bytes))) {
            ZipEntry entry;
            while ((entry = zip.getNextEntry()) != null) {
                if (entry.isDirectory()) {
                    continue;
                }
                if (files.size() >= maxFileCount) {
                    throw new IllegalArgumentException(
                            "Skill package exceeds max file count of " + maxFileCount);
                }
                String path = normalizeEntryName(entry.getName());
                if (contentByPath.containsKey(path)) {
                    throw new IllegalArgumentException(
                            "Skill package contains duplicate path: " + path);
                }
                MessageDigest digest = MessageDigest.getInstance("SHA-256");
                long size = 0;
                ByteArrayOutputStream content = new ByteArrayOutputStream();
                byte[] buffer = new byte[8192];
                int read;
                while ((read = zip.read(buffer)) >= 0) {
                    digest.update(buffer, 0, read);
                    content.write(buffer, 0, read);
                    size += read;
                    totalUncompressedBytes += read;
                    if (size > maxPackageBytes) {
                        throw new IllegalArgumentException(
                                "Skill package contains oversized file: " + path);
                    }
                    if (totalUncompressedBytes > maxUncompressedBytes) {
                        throw new IllegalArgumentException(

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Rebuild the zip ensuring each logical path appears exactly once with forward slashes and no './' prefix.
  2. On Windows, use a zip tool that normalizes to forward slashes, or normalize paths in the build script.
  3. List the zip contents (unzip -l) and dedupe before uploading.

Example fix

# before: zip contains both ./SKILL.md and SKILL.md
# after: rebuild without path prefixes
zip skill.zip SKILL.md scripts/run.sh references/doc.md
Defensive patterns

Strategy: validation

Validate before calling

// Before uploading, detect duplicate normalized paths
Set<String> seen = new HashSet<>();
try (var z = new ZipFile(packageFile)) {
    for (var e : Collections.list(z.entries())) {
        if (e.isDirectory()) continue;
        String norm = e.getName().replace('\\','/').replaceAll("^\\./", "");
        if (!seen.add(norm)) throw new IllegalStateException("duplicate path: " + norm);
    }
}

Type guard

static boolean noDuplicatePaths(java.io.File zip) throws java.io.IOException {
    Set<String> seen = new HashSet<>();
    try (var z = new ZipFile(zip)) {
        for (var e : Collections.list(z.entries())) {
            if (e.isDirectory()) continue;
            if (!seen.add(e.getName().replace('\\','/').replaceAll("^\\./",""))) return false;
        }
    }
    return true;
}

Try / catch

try { skillRegistryService.register(manifest, pkg); }
catch (IllegalArgumentException e) {
    if (e.getMessage().contains("duplicate path")) { /* rebuild zip with unique paths */ }
    else throw e;
}

Prevention

When it happens

Trigger: POST /api/skills/register with a zip that contains both 'SKILL.md' and './SKILL.md', or 'scripts\run.sh' alongside 'scripts/run.sh'. Also when a zip tool emits a path twice with different separators.

Common situations: Building the zip on Windows producing backslash paths mixed with forward slashes; a packaging script that adds a './' prefix to some entries; zipping the same file from two source locations into the same target path.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/a61dad6494c813f8. Report an issue: GitHub.