alibaba/nacos · error · NacosException
SERVER_ERROR
SERVER_ERROR
Error message
Failed to create skill zip: ${e.getMessage()} What it means
Thrown by SkillRequestUtil.buildSkillZipResponse when SkillUtils.toZipBytes(skill) fails during a skill export/download operation. The method serializes a Skill domain object into ZIP bytes and builds a ResponseEntity with application/zip content type and Content-Disposition headers. Any exception — IO failure during ZIP streaming, null fields on the Skill object, or serialization issues — is caught and re-wrapped as NacosException with SERVER_ERROR (500).
Source
Thrown at ai/src/main/java/com/alibaba/nacos/ai/utils/SkillRequestUtil.java:70
/**
* Build a ZIP download {@link ResponseEntity} from a {@link Skill} object.
*
* <p>Shared by all controllers that need to export a skill as ZIP.</p>
*
* @param skill the Skill object
* @return ResponseEntity containing ZIP bytes with proper headers
* @throws NacosException if ZIP creation fails
*/
public static ResponseEntity<byte[]> buildSkillZipResponse(Skill skill) throws NacosException {
try {
byte[] zipBytes = SkillUtils.toZipBytes(skill);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/zip"));
headers.add("Content-Disposition", "attachment;filename=" + skill.getName() + ".zip");
return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);
} catch (Exception e) {
throw new NacosException(NacosException.SERVER_ERROR,
"Failed to create skill zip: " + e.getMessage(), e);
}
}
/**
* Build a ZIP download {@link ResponseEntity} together with the listener-related headers
* ({@code ETag}, {@code X-Nacos-Skill-Md5} and {@code X-Nacos-Skill-Resolved-Version}).
*
* <p>{@code md5} and {@code resolvedVersion} may be blank; only non-blank values are emitted as
* headers so legacy paths that do not yet carry MD5 keep their existing response shape.
*
* @param skill the Skill object
* @param md5 published content MD5, optional
* @param resolvedVersion resolved version when caller queries by label, optional
* @return ResponseEntity containing ZIP bytes with proper headers
* @throws NacosException if ZIP creation fails
*/
public static ResponseEntity<byte[]> buildSkillZipResponseWithMd5(Skill skill, String md5,View on GitHub (pinned to 9b989acdf1)
Solutions
- Check server logs for the chained cause exception (e) to identify whether the failure is a null field, IO error, or serialization issue.
- Verify the Skill object retrieved from storage is complete — non-null name, description, skillMd, and resource map — before the export endpoint is reached.
- If the skill was recently migrated or imported, re-import it from a known-good ZIP to ensure all fields are populated.
- File a bug if the cause is a null field in a Skill that should always be complete — the export path should validate before attempting serialization.
Example fix
// before — buildSkillZipResponse throws SERVER_ERROR on null skill.getName()
// (no caller-side fix; this is a server-side integrity issue)
// after — guard in the controller before calling buildSkillZipResponse
if (skill == null || StringUtils.isBlank(skill.getName()) || StringUtils.isBlank(skill.getSkillMd())) {
throw new NacosApiException(NacosApiException.INVALID_PARAM,
ErrorCode.DATA_EMPTY, "Skill data is incomplete and cannot be exported");
}
return SkillRequestUtil.buildSkillZipResponse(skill); Defensive patterns
Strategy: try-catch
Validate before calling
// Validate skill completeness before calling buildSkillZipResponse
if (skill == null || StringUtils.isBlank(skill.getName())
|| StringUtils.isBlank(skill.getSkillMd())) {
throw new IllegalStateException("Skill is incomplete; cannot export as ZIP");
} Type guard
public static boolean isExportableSkill(Skill skill) {
return skill != null
&& StringUtils.isNotBlank(skill.getName())
&& StringUtils.isNotBlank(skill.getSkillMd());
} Try / catch
try {
return SkillRequestUtil.buildSkillZipResponse(skill);
} catch (NacosException e) {
if (e.getErrCode() == NacosException.SERVER_ERROR) {
log.error("Skill ZIP export failed for skill [{}]", skill.getName(), e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
throw e;
} Prevention
- Ensure Skill objects in storage always have non-null name, description, and skillMd before they become exportable.
- Add a service-layer integrity check before the export endpoint: reject skills with null required fields.
- Monitor server logs for 'Failed to create skill zip' to catch storage corruption early.
When it happens
Trigger: Calling GET on a skill export/download endpoint (admin or console) where the underlying Skill object retrieved from storage has corrupted or null fields (e.g. null name used in Content-Disposition header filename, null skillMd content), or where SkillUtils.toZipBytes encounters an I/O error writing the archive to its ByteArrayOutputStream.
Common situations: Skill was partially written to storage with a null skillMd or null resource map; a storage migration left a Skill record in an inconsistent state; concurrent deletion removed the skill between the fetch and the ZIP build; a custom SkillUtils or SkillResource subclass throws during serialization.
Related errors
- Failed to create skill well-known archive: " + e.getMessage(
- DATA_ACCESS_ERROR
- PARAMETER_MISSING
- DATA_ACCESS_ERROR
- RESOURCE_NOT_FOUND
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/414396582f799162.
Report an issue: GitHub.