conductor-oss/conductor · error · IllegalArgumentException

Skill package contains duplicate script tool name: {toolName

Error message

Skill package contains duplicate script tool name: {toolName}

What it means

Thrown by parseSkillPackage when two script files under scripts/ map to the same tool name. scriptToolName strips the file extension, so scripts/run.py and scripts/run.sh both become the tool name 'run'. Skill scripts are exposed as tools by their base filename, so tool names must be unique within the package.

Source

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

        Map<String, String> agentFiles = new LinkedHashMap<>();
        Map<String, Map<String, Object>> scripts = new LinkedHashMap<>();
        List<String> resourceFiles = new ArrayList<>();

        for (String path : contentByPath.keySet()) {
            if (path.equals("SKILL.md")) {
                continue;
            }
            if (isRootAgentFile(path)) {
                agentFiles.put(
                        path.substring(0, path.length() - "-agent.md".length()),
                        decodeUtf8(path, contentByPath.get(path)));
                continue;
            }
            if (isScriptFile(path)) {
                String filename = path.substring("scripts/".length());
                String toolName = scriptToolName(filename);
                if (scripts.containsKey(toolName)) {
                    throw new IllegalArgumentException(
                            "Skill package contains duplicate script tool name: " + toolName);
                }
                Map<String, Object> info = new LinkedHashMap<>();
                info.put("filename", filename);
                info.put("language", detectScriptLanguage(filename));
                scripts.put(toolName, info);
                continue;
            }
            if (isResourceFile(path)) {
                resourceFiles.add(path);
            }
        }

        Map<String, Object> rawConfig = new LinkedHashMap<>();
        rawConfig.put("model", resolveModel(manifest));
        rawConfig.put("agentModels", resolveAgentModels(manifest));
        rawConfig.put("skillMd", skillMd);
        rawConfig.put("agentFiles", agentFiles);

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Rename one of the scripts so the base filenames differ, e.g. scripts/run.py and scripts/run-shell.sh.
  2. Remove the obsolete script variant before zipping.
  3. Keep exactly one language per logical tool name.

Example fix

# before: scripts/run.py and scripts/run.sh collide on tool name 'run'
# after: rename one
mv scripts/run.sh scripts/run-bash.sh
Defensive patterns

Strategy: validation

Validate before calling

// Before zipping, ensure script base filenames are unique
Set<String> toolNames = new HashSet<>();
for (Path p : scriptsDirFiles) {
    String fn = p.getFileName().toString();
    String tool = fn.contains(".") ? fn.substring(0, fn.lastIndexOf('.')) : fn;
    if (!toolNames.add(tool)) throw new IllegalStateException("duplicate tool name: " + tool);
}

Type guard

static boolean uniqueScriptToolNames(List<String> scriptFilenames) {
    Set<String> seen = new HashSet<>();
    for (String fn : scriptFilenames) {
        String tool = fn.contains(".") ? fn.substring(0, fn.lastIndexOf('.')) : fn;
        if (!seen.add(tool)) return false;
    }
    return true;
}

Try / catch

try { skillRegistryService.register(manifest, pkg); }
catch (IllegalArgumentException e) {
    if (e.getMessage().contains("duplicate script tool name")) { /* rename one script */ }
    else throw e;
}

Prevention

When it happens

Trigger: POST /api/skills/register with a zip containing scripts/run.py AND scripts/run.sh (or scripts/parse.js and scripts/parse.ts). The second one encountered triggers the duplicate detection.

Common situations: Providing both a Python and a shell variant of the same tool; porting a script to a new language and leaving the old one in scripts/; two scripts that differ only by extension.

Related errors


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