alibaba/nacos · error · IllegalArgumentException

Skill name cannot be blank

Error message

Skill name cannot be blank

What it means

SkillUtils.toZipBytes throws IllegalArgumentException when the Skill object is non-null but its getName() returns a blank value. The skill name is used as the root directory in the ZIP structure (skillName/SKILL.md), so it must be a valid non-blank identifier.

Source

Thrown at api/src/main/java/com/alibaba/nacos/api/ai/model/skills/SkillUtils.java:115

    
    /**
     * Convert Skill object to a ZIP byte array containing all skill files.
     *
     * <p>The ZIP structure mirrors the upload format:
     * {@code skillName/SKILL.md}, {@code skillName/type/resourceName}, etc.
     * Binary resources (marked with metadata encoding=base64) are decoded back to raw bytes.</p>
     *
     * @param skill the Skill object to convert
     * @return ZIP file as byte array
     * @throws IOException if ZIP creation fails
     * @throws IllegalArgumentException if skill is null or skill name is blank
     */
    public static byte[] toZipBytes(Skill skill) throws IOException {
        if (skill == null) {
            throw new IllegalArgumentException("Skill cannot be null");
        }
        if (StringUtils.isBlank(skill.getName())) {
            throw new IllegalArgumentException("Skill name cannot be blank");
        }
        
        String skillName = skill.getName();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (ZipOutputStream zos = new ZipOutputStream(baos)) {
            // 1. SKILL.md
            zos.putNextEntry(new ZipEntry(skillName + "/SKILL.md"));
            zos.write(toMarkdown(skill).getBytes(StandardCharsets.UTF_8));
            zos.closeEntry();
            
            // 2. Resource files
            if (skill.getResource() != null && !skill.getResource().isEmpty()) {
                for (SkillResource resource : skill.getResource().values()) {
                    if (resource == null || StringUtils.isBlank(resource.getName())) {
                        continue;
                    }
                    String entryPath = buildZipEntryPath(skillName, resource);
                    zos.putNextEntry(new ZipEntry(entryPath));

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Validate skill.getName() is non-blank before calling toZipBytes.
  2. Enforce name presence at the Skill builder or constructor level.
  3. Return a validation error to the API caller when name is missing.

Example fix

// before
Skill skill = new Skill();
skill.setResource(resources);
// name never set
byte[] zip = SkillUtils.toZipBytes(skill); // throws

// after
Skill skill = new Skill();
skill.setName("my-skill");
skill.setResource(resources);
byte[] zip = SkillUtils.toZipBytes(skill); // ok
Defensive patterns

Strategy: validation

Validate before calling

if (skill == null || StringUtils.isBlank(skill.getName())) {
    throw new IllegalArgumentException("Skill name is required");
}
byte[] zip = SkillUtils.toZipBytes(skill);

Type guard

public static boolean hasValidSkillName(Skill skill) {
    return skill != null && skill.getName() != null && !skill.getName().trim().isEmpty();
}

Try / catch

try {
    byte[] zip = SkillUtils.toZipBytes(skill);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Skill name cannot be blank")) {
        return badRequest("Skill name is required");
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling toZipBytes with a Skill whose name field is null, empty, or whitespace. Happens when a Skill object is partially constructed or deserialized from JSON that omits the name field.

Common situations: A Skill object built from a request body where the name field was absent. A deserialized Skill from a malformed config. A test fixture that forgot to set the name.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/700dd36f962f98bf. Report an issue: GitHub.