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
- Rename one of the scripts so the base filenames differ, e.g. scripts/run.py and scripts/run-shell.sh.
- Remove the obsolete script variant before zipping.
- 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
- Keep one language per logical tool; remove superseded variants before zipping.
- Name scripts by their distinct purpose, not just by extension.
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
- Skill package contains duplicate path: {path}
- Invalid skill package zip: {e.getMessage()}
- Skill package is missing SKILL.md
- Skill manifest name '{manifestName}' does not match package
- Skill {name} version {version} already exists with a differe
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/238ae56f51d43b04.
Report an issue: GitHub.