{"record":{"id":"414396582f799162","repo":"alibaba/nacos","slug":"server-error-414396","errorCode":"SERVER_ERROR","errorMessage":"Failed to create skill zip: ${e.getMessage()}","messagePattern":"Failed to create skill zip: (.+?)","errorType":"exception","errorClass":"NacosException","httpStatus":500,"severity":"error","filePath":"ai/src/main/java/com/alibaba/nacos/ai/utils/SkillRequestUtil.java","lineNumber":70,"sourceCode":"    \n    /**\n     * Build a ZIP download {@link ResponseEntity} from a {@link Skill} object.\n     *\n     * <p>Shared by all controllers that need to export a skill as ZIP.</p>\n     *\n     * @param skill the Skill object\n     * @return ResponseEntity containing ZIP bytes with proper headers\n     * @throws NacosException if ZIP creation fails\n     */\n    public static ResponseEntity<byte[]> buildSkillZipResponse(Skill skill) throws NacosException {\n        try {\n            byte[] zipBytes = SkillUtils.toZipBytes(skill);\n            HttpHeaders headers = new HttpHeaders();\n            headers.setContentType(MediaType.parseMediaType(\"application/zip\"));\n            headers.add(\"Content-Disposition\", \"attachment;filename=\" + skill.getName() + \".zip\");\n            return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);\n        } catch (Exception e) {\n            throw new NacosException(NacosException.SERVER_ERROR,\n                \"Failed to create skill zip: \" + e.getMessage(), e);\n        }\n    }\n    \n    /**\n     * Build a ZIP download {@link ResponseEntity} together with the listener-related headers\n     * ({@code ETag}, {@code X-Nacos-Skill-Md5} and {@code X-Nacos-Skill-Resolved-Version}).\n     *\n     * <p>{@code md5} and {@code resolvedVersion} may be blank; only non-blank values are emitted as\n     * headers so legacy paths that do not yet carry MD5 keep their existing response shape.\n     *\n     * @param skill           the Skill object\n     * @param md5             published content MD5, optional\n     * @param resolvedVersion resolved version when caller queries by label, optional\n     * @return ResponseEntity containing ZIP bytes with proper headers\n     * @throws NacosException if ZIP creation fails\n     */\n    public static ResponseEntity<byte[]> buildSkillZipResponseWithMd5(Skill skill, String md5,","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/ai/src/main/java/com/alibaba/nacos/ai/utils/SkillRequestUtil.java#L52-L88","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before — buildSkillZipResponse throws SERVER_ERROR on null skill.getName()\n// (no caller-side fix; this is a server-side integrity issue)\n\n// after — guard in the controller before calling buildSkillZipResponse\nif (skill == null || StringUtils.isBlank(skill.getName()) || StringUtils.isBlank(skill.getSkillMd())) {\n    throw new NacosApiException(NacosApiException.INVALID_PARAM,\n        ErrorCode.DATA_EMPTY, \"Skill data is incomplete and cannot be exported\");\n}\nreturn SkillRequestUtil.buildSkillZipResponse(skill);","handlingStrategy":"try-catch","validationCode":"// Validate skill completeness before calling buildSkillZipResponse\nif (skill == null || StringUtils.isBlank(skill.getName())\n    || StringUtils.isBlank(skill.getSkillMd())) {\n    throw new IllegalStateException(\"Skill is incomplete; cannot export as ZIP\");\n}","typeGuard":"public static boolean isExportableSkill(Skill skill) {\n    return skill != null\n        && StringUtils.isNotBlank(skill.getName())\n        && StringUtils.isNotBlank(skill.getSkillMd());\n}","tryCatchPattern":"try {\n    return SkillRequestUtil.buildSkillZipResponse(skill);\n} catch (NacosException e) {\n    if (e.getErrCode() == NacosException.SERVER_ERROR) {\n        log.error(\"Skill ZIP export failed for skill [{}]\", skill.getName(), e);\n        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["skill","zip-export","server-error","serialization"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}