conductor-oss/conductor · error · IllegalArgumentException
Skill {name} version {version} already exists with a differe
Error message
Skill {name} version {version} already exists with a different checksum What it means
Thrown by register() when a skill with the same name AND version already exists in the metadata store, but the uploaded package's SHA-256 checksum differs from the stored record. This is idempotency protection: a name+version pair is immutable once stored. Re-uploading identical bytes is allowed (and re-stores the package if missing), but different bytes under the same version is rejected.
Source
Thrown at agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java:175
+ "' does not match package SKILL.md name '"
+ name
+ "'");
}
String version = stringValue(manifest.get("version"));
if (version == null || version.isBlank()) {
version = checksum.substring(0, 12);
}
validateVersion(version);
pinRegisteredCrossSkillRefs(rawConfig);
long now = Instant.now().toEpochMilli();
Optional<SkillDetail> existingOpt = metadataDao.find(name, version);
if (existingOpt.isPresent()) {
SkillDetail existing = existingOpt.get();
if (!checksum.equals(existing.getChecksum())) {
throw new IllegalArgumentException(
"Skill "
+ name
+ " version "
+ version
+ " already exists with a different checksum");
}
if (!packageExists(existing)) {
StoredSkillPackage restored = packageStore.store(name, version, checksum, bytes);
existing.setPackageFileHandleId(restored.handle());
existing.setStorageType(restored.storageType());
existing.setPackageSize(restored.size());
existing.setUpdatedAt(now);
metadataDao.save(existing, false);
}
return existing;
}
StoredSkillPackage stored = null;View on GitHub (pinned to cf7c3e4a8a)
Solutions
- Bump the version field in the manifest (e.g. 1.0.0 -> 1.0.1) so the new content gets a distinct version slot.
- If you intended to replace the existing content, delete the old version first: DELETE /api/skills/{name}/versions/{version}, then re-register.
- If the new upload should be identical, confirm the zip bytes are unchanged — re-export from the same source the original used.
Example fix
// before: register name=foo version=1.0.0 checksum=aaa... then again with checksum=bbb...
// after — bump version on the second upload:
{"name":"foo","version":"1.0.1"} Defensive patterns
Strategy: validation
Validate before calling
// Before register, check whether name+version exists and whether the checksum differs
byte[] bytes = pkg.getBytes();
String checksum = sha256Hex(bytes);
Optional<SkillDetail> existing = metadataDao.find(name, version); // if you have DAO access
if (existing.isPresent() && !checksum.equals(existing.get().getChecksum())) {
// bump version or delete first
} Type guard
// Client-side: is this version safe to (re)upload?
boolean safeToUpload(String name, String version, String localChecksum, SkillRegistryClient c) {
try { return localChecksum.equals(c.get(name, version).getChecksum()); }
catch (RuntimeException notFound) { return true; }
} Try / catch
try { skillRegistryService.register(manifest, pkg); }
catch (IllegalArgumentException e) {
if (e.getMessage().contains("already exists with a different checksum")) {
// bump version in manifest and retry, or DELETE then re-register
} else throw e;
} Prevention
- Derive the version from content (e.g. a content hash or semantic bump) so changed bytes always mean a new version.
- Make register idempotent in pipelines: if get(name, version) returns the same checksum, skip the upload.
When it happens
Trigger: POST /api/skills/register twice with name=foo version=1.0.0 but different zip contents. Common when version is pinned explicitly in the manifest and the zip was rebuilt with changed files between uploads.
Common situations: Forgetting to bump the version after editing skill files; re-running a deploy pipeline that hardcodes a version string; two teams pushing the same version number for different content.
Related errors
- Skill manifest name '{manifestName}' does not match package
- File path is required
- skillRef is required
- Skill manifest is required
- Invalid skill manifest JSON: {e.getMessage()}
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/f2768ca8ea3f8f1b.
Report an issue: GitHub.