{"record":{"id":"f2768ca8ea3f8f1b","repo":"conductor-oss/conductor","slug":"skill-name-version-version-already-exists-with","errorCode":null,"errorMessage":"Skill {name} version {version} already exists with a different checksum","messagePattern":"Skill (.+?) version (.+?) already exists with a different checksum","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java","lineNumber":175,"sourceCode":"                            + \"' does not match package SKILL.md name '\"\n                            + name\n                            + \"'\");\n        }\n\n        String version = stringValue(manifest.get(\"version\"));\n        if (version == null || version.isBlank()) {\n            version = checksum.substring(0, 12);\n        }\n        validateVersion(version);\n        pinRegisteredCrossSkillRefs(rawConfig);\n\n        long now = Instant.now().toEpochMilli();\n\n        Optional<SkillDetail> existingOpt = metadataDao.find(name, version);\n        if (existingOpt.isPresent()) {\n            SkillDetail existing = existingOpt.get();\n            if (!checksum.equals(existing.getChecksum())) {\n                throw new IllegalArgumentException(\n                        \"Skill \"\n                                + name\n                                + \" version \"\n                                + version\n                                + \" already exists with a different checksum\");\n            }\n            if (!packageExists(existing)) {\n                StoredSkillPackage restored = packageStore.store(name, version, checksum, bytes);\n                existing.setPackageFileHandleId(restored.handle());\n                existing.setStorageType(restored.storageType());\n                existing.setPackageSize(restored.size());\n                existing.setUpdatedAt(now);\n                metadataDao.save(existing, false);\n            }\n            return existing;\n        }\n\n        StoredSkillPackage stored = null;","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java#L157-L193","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: register name=foo version=1.0.0 checksum=aaa... then again with checksum=bbb...\n// after — bump version on the second upload:\n{\"name\":\"foo\",\"version\":\"1.0.1\"}","handlingStrategy":"validation","validationCode":"// Before register, check whether name+version exists and whether the checksum differs\nbyte[] bytes = pkg.getBytes();\nString checksum = sha256Hex(bytes);\nOptional<SkillDetail> existing = metadataDao.find(name, version); // if you have DAO access\nif (existing.isPresent() && !checksum.equals(existing.get().getChecksum())) {\n    // bump version or delete first\n}","typeGuard":"// Client-side: is this version safe to (re)upload?\nboolean safeToUpload(String name, String version, String localChecksum, SkillRegistryClient c) {\n    try { return localChecksum.equals(c.get(name, version).getChecksum()); }\n    catch (RuntimeException notFound) { return true; }\n}","tryCatchPattern":"try { skillRegistryService.register(manifest, pkg); }\ncatch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"already exists with a different checksum\")) {\n        // bump version in manifest and retry, or DELETE then re-register\n    } else throw e;\n}","preventionTips":["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."],"tags":["java","conductor","skill-registry","idempotency","validation"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}