alibaba/nacos · error · NacosApiException
20004
20004
Error message
Skill not found after deleting draft: {name} What it means
A NOT_FOUND (HTTP 404, ErrorCode RESOURCE_NOT_FOUND/20004) from deleteDraftAndCreateUploadedSkill: after doDeleteDraft removed the editing draft, re-fetching the meta returned null — the entire skill was concurrently deleted between the two steps. The replace operation cannot continue because its target resource no longer exists.
Source
Thrown at ai/src/main/java/com/alibaba/nacos/ai/service/skills/SkillOperationServiceImpl.java:567
private String deleteDraftAndCreateUploadedSkill(String namespaceId, Skill skill,
String targetVersion, AiResource meta, String commitMsg) throws NacosException {
String name = skill.getName();
if (meta == null) {
throw new NacosApiException(NacosException.CONFLICT, ErrorCode.RESOURCE_CONFLICT,
"No editing draft to delete: " + name);
}
checkWritableUploadResource(meta);
ResourceVersionInfo info = AiResourceManager.requireVersionInfo(meta);
ensureNoReviewingVersion(info, "replace upload draft");
if (StringUtils.isBlank(info.getEditingVersion())) {
throw new NacosApiException(NacosException.CONFLICT, ErrorCode.RESOURCE_CONFLICT,
"No editing draft to delete: " + name);
}
resourceManager.doDeleteDraft(namespaceId, name, RESOURCE_TYPE_SKILL,
v -> deleteSkillStorageForVersion(namespaceId, name, v.getVersion(), v.getStorage()));
AiResource latestMeta = resourceManager.findMeta(namespaceId, name, RESOURCE_TYPE_SKILL);
if (latestMeta == null) {
throw new NacosApiException(NacosException.NOT_FOUND, ErrorCode.RESOURCE_NOT_FOUND,
"Skill not found after deleting draft: " + name);
}
createDraftWithSkill(namespaceId, skill, targetVersion, latestMeta, false, commitMsg);
return name;
}
private static void ensureNoReviewingVersion(ResourceVersionInfo info, String action)
throws NacosApiException {
if (info != null && StringUtils.isNotBlank(info.getReviewingVersion())) {
throw new NacosApiException(NacosException.CONFLICT, ErrorCode.RESOURCE_CONFLICT,
"There is already a reviewing version: " + info.getReviewingVersion()
+ ", cannot " + action);
}
}
/**
* Resolve the upload version for strict call sites.
* Priority: SKILL.md YAML front-matter (version / metadata.version) -> meta.json in ZIP -> user-specified targetVersion -> default "0.0.1".View on GitHub (pinned to 9b989acdf1)
Solutions
- Treat the skill as gone; re-run precheck to confirm current state.
- If the skill should still exist, recreate it with CREATE_DRAFT.
- Prevent concurrent delete + replace on the same resource (serialize lifecycle ops).
Defensive patterns
Strategy: try-catch
Try / catch
try {
skillOp.uploadSkillFromZip(req); // DELETE_DRAFT_AND_CREATE
} catch (NacosApiException e) {
if (e.getErrCode() == NacosException.NOT_FOUND
&& ErrorCode.RESOURCE_NOT_FOUND.getCode() == e.getDetailErrCode()
&& e.getErrMsg().contains("after deleting draft")) {
// resource was concurrently deleted: re-precheck and CREATE_DRAFT if it should exist
List<SkillUploadPrecheckResult> pc = skillOp.precheckUploadSkillFromZip(ns, zipBytes);
// ... decide from pc ...
} else {
throw e;
}
} Prevention
- Avoid concurrent delete and upload/replace on the same resource.
- After a delete-draft step, re-precheck before continuing a replace flow.
- Treat 'not found after deleting draft' as 'resource gone — recreate if needed'.
When it happens
Trigger: A concurrent deleteSkill (or namespace/resource removal) racing with a DELETE_DRAFT_AND_CREATE upload: the draft delete succeeds, then the meta lookup finds nothing.
Common situations: Two operators, one deleting the skill while another replaces its draft; automation deleting resources mid-upload; partial retry after an earlier failure.
Related errors
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/eeb6d207f131cdc0.
Report an issue: GitHub.