{"record":{"id":"f5a928dc517cc29e","repo":"alibaba/nacos","slug":"parsing-data-failed-f5a928","errorCode":"PARSING_DATA_FAILED","errorMessage":"Failed to parse zip file: \" + e.getMessage()","messagePattern":"Failed to parse zip file: \" \\+ e\\.getMessage\\(\\)","errorType":"exception","errorClass":"NacosApiException","httpStatus":400,"severity":"error","filePath":"ai/src/main/java/com/alibaba/nacos/ai/utils/SkillZipParser.java","lineNumber":248,"sourceCode":"            if (StringUtils.isBlank(skillMdContent)) {\n                throw new NacosApiException(NacosApiException.INVALID_PARAM,\n                    ErrorCode.PARAMETER_VALIDATE_ERROR,\n                    \"SKILL.md file not found in zip\");\n            }\n            \n            Skill skill = parseSkillMarkdown(skillMdContent, namespaceId);\n            List<ZipEntryData> resourceEntries =\n                filterEntriesByPrefix(entries, getSkillPrefix(skillMdEntry.name));\n            Map<String, SkillResource> resources =\n                parseResources(resourceEntries, skill.getName(), SKILL_MD_FILE);\n            skill.setResource(resources);\n            \n            return skill;\n        } catch (NacosApiException e) {\n            throw e;\n        } catch (Exception e) {\n            LOGGER.error(\"Failed to parse skill zip file\", e);\n            throw new NacosApiException(NacosApiException.INVALID_PARAM,\n                ErrorCode.PARSING_DATA_FAILED,\n                \"Failed to parse zip file: \" + e.getMessage());\n        }\n    }\n    \n    /**\n     * Parse multiple skills from a single zip archive. Supports zip files containing multiple skill subdirectories,\n     * each with its own SKILL.md. If only one SKILL.md is found, returns a list with a single element.\n     *\n     * <p>Expected zip structure for multi-skill:\n     * <pre>\n     * skills.zip\n     * ├── skill-a/\n     * │   ├── SKILL.md\n     * │   └── resource.txt\n     * ├── skill-b/\n     * │   ├── SKILL.md\n     * │   └── template/prompt.md","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/ai/src/main/java/com/alibaba/nacos/ai/utils/SkillZipParser.java#L230-L266","documentation":"Thrown by SkillZipParser.parseSkillFromZip as the catch-all for any non-NacosApiException exception during ZIP parsing. This covers failures in unzipToEntries (ZipArchiveInputStream errors, security-limit violations via NacosRuntimeException), parseSkillMarkdown (invalid YAML, missing frontmatter), and parseResources. The original exception is logged and its message is included in the error.","triggerScenarios":"Uploading a ZIP that triggers any unexpected exception during parsing: a corrupted ZIP archive that Apache Commons Compress cannot read; a path-traversal entry ('../') caught by SkillUtils.validatePathSafety; a ZIP bomb exceeding the uncompressed size limit; a SKILL.md with malformed YAML frontmatter; a resource entry with an invalid name pattern.","commonSituations":"Corrupted or truncated ZIP file from a failed download; a ZIP created by a tool that produces entries Apache Commons Compress cannot handle; a malicious or accidental path-traversal entry in the ZIP; exceeding the max-entries or max-uncompressed-size limits; SKILL.md YAML frontmatter that is syntactically broken (e.g. missing colon, unbalanced quotes).","solutions":["Check server logs for the full stack trace — the chained exception (e) identifies the exact cause.","If the ZIP is corrupted, re-download or re-create it from the source.","If the error is a security-limit violation (too many entries, uncompressed size exceeded), raise nacos.ai.skill.zip.max-entries or nacos.ai.skill.zip.max-uncompressed-size-mb if the skill legitimately needs more.","If the error is a path-traversal rejection, inspect the ZIP for entries containing '..' or absolute paths and remove them.","If the error is YAML-related, validate the SKILL.md frontmatter syntax with a YAML linter before zipping."],"exampleFix":"// before — ZIP contains a path-traversal entry\n// entry: ../../../etc/passwd\n\n// after — re-create ZIP without malicious entries\n// zip -r skill.zip SKILL.md resources/  (from inside the skill directory)\n// verify: unzip -l skill.zip  (no entries with '..')","handlingStrategy":"try-catch","validationCode":"// Pre-validate ZIP structure before calling parseSkillFromZip\nif (zipBytes == null || zipBytes.length == 0) {\n    throw new IllegalArgumentException(\"ZIP is empty\");\n}\n// Check ZIP magic bytes\nif (zipBytes.length < 4 || (zipBytes[0] != 0x50 || zipBytes[1] != 0x4B)) {\n    throw new IllegalArgumentException(\"Not a valid ZIP file (missing PK magic bytes)\");\n}","typeGuard":"public static boolean isValidZipArchive(byte[] zipBytes) {\n    return zipBytes != null && zipBytes.length >= 4\n        && zipBytes[0] == 0x50 && zipBytes[1] == 0x4B // PK magic\n        && zipBytes.length <= SkillZipParser.resolveMaxUploadBytes();\n}","tryCatchPattern":"try {\n    Skill skill = SkillZipParser.parseSkillFromZip(zipBytes, namespaceId);\n} catch (NacosApiException e) {\n    if (ErrorCode.PARSING_DATA_FAILED.equals(e.getErrDetail())) {\n        log.error(\"Failed to parse skill ZIP: {}\", e.getErrMsg(), e);\n        return ResponseEntity.badRequest()\n            .body(\"Could not parse the ZIP file. Check the archive integrity and SKILL.md format. Detail: \"\n                + e.getErrMsg());\n    }\n    throw e;\n}","preventionTips":["Validate the ZIP magic bytes (PK) before parsing to catch non-ZIP files early.","Run unzip -t skill.zip to test archive integrity before uploading.","Validate SKILL.md YAML frontmatter syntax with a YAML linter.","Inspect ZIP entries for path traversal ('..') before uploading.","Raise max-entries / max-uncompressed-size-mb if legitimate large skills are rejected."],"tags":["skill","zip-parsing","parse-error","catch-all"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}