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

  1. Treat the skill as gone; re-run precheck to confirm current state.
  2. If the skill should still exist, recreate it with CREATE_DRAFT.
  3. 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

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.