{"record":{"id":"18ce8f7e9c67dbb1","repo":"alibaba/nacos","slug":"invalid-zip-data-missing-zip-magic-header-pk-x03","errorCode":null,"errorMessage":"Invalid ZIP data: missing ZIP magic header (PK\\x03\\x04)","messagePattern":"Invalid ZIP data: missing ZIP magic header \\(PK\\\\x03\\\\x04\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/com/alibaba/nacos/api/ai/model/skills/SkillUtils.java","lineNumber":207,"sourceCode":"            throw new SecurityException(\n                \"Path escapes target directory: \" + target + \" is outside \" + baseDir);\n        }\n    }\n    \n    /**\n     * Validate that byte array is a valid ZIP file by checking the magic number header.\n     *\n     * @param data the byte array to validate\n     * @throws IllegalArgumentException if data is null, too short, or does not have ZIP magic header\n     */\n    public static void validateZipBytes(byte[] data) {\n        if (data == null || data.length < ZIP_MIN_SIZE) {\n            throw new IllegalArgumentException(\n                \"Invalid ZIP data: too short (\" + (data == null ? 0 : data.length) + \" bytes)\");\n        }\n        for (int i = 0; i < ZIP_MAGIC.length; i++) {\n            if (data[i] != ZIP_MAGIC[i]) {\n                throw new IllegalArgumentException(\n                    \"Invalid ZIP data: missing ZIP magic header (PK\\\\x03\\\\x04)\");\n            }\n        }\n    }\n    \n    /**\n     * Validate all ZIP entry paths for path traversal and absolute paths.\n     *\n     * <p>Scans entry names only without decompressing content, so it is lightweight\n     * and suitable for validating downloaded ZIP bytes on the client side.</p>\n     *\n     * @param data the ZIP byte array to validate\n     * @throws SecurityException if any entry contains path traversal or absolute path\n     * @throws IOException if ZIP cannot be read\n     */\n    public static void validateZipEntryPaths(byte[] data) throws IOException {\n        try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(data))) {\n            ZipEntry entry;","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/api/src/main/java/com/alibaba/nacos/api/ai/model/skills/SkillUtils.java#L189-L225","documentation":"Thrown by SkillUtils.validateZipBytes as an IllegalArgumentException when the byte array is at least 30 bytes long but its first four bytes are not the ZIP local-file-header signature 0x50 0x4B 0x03 0x04 ('PK\\x03\\x04'). This detects data that is the wrong format (e.g. a gzip, tar, or text body) masquerading as a ZIP.","triggerScenarios":"Calling validateZipBytes on a byte array whose magic number differs — e.g. a gzip stream (0x1f 0x8b), a plain JSON/text body, or a tar archive. Often happens when the skill content field held non-ZIP data or the server returned an error page instead of a ZIP.","commonSituations":"The skill 'content' was a raw markdown string rather than a ZIP; a CDN/proxy returned an HTML error page (200 with text) that was buffered as bytes; the producer used tar.gz instead of zip.","solutions":["Confirm the producer actually created a standard ZIP (PK\\x03\\x04) and not gzip/tar.","Inspect the first bytes of the array (HexFormat.of().formatHex) to identify the real format.","Re-export the skill as a ZIP and re-upload to the server."],"exampleFix":"// before\nbyte[] data = \"{\\\"error\\\":\\\"not found\\\"}\".getBytes();\nSkillUtils.validateZipBytes(data); // throws: missing magic\n\n// after\nbyte[] data = SkillUtils.toZipBytes(skill); // produces valid PK ZIP\nSkillUtils.validateZipBytes(data); // ok","handlingStrategy":"validation","validationCode":"static boolean hasZipMagic(byte[] data) {\n    return data != null && data.length >= 4\n        && (data[0] & 0xFF) == 0x50 && (data[1] & 0xFF) == 0x4B\n        && (data[2] & 0xFF) == 0x03 && (data[3] & 0xFF) == 0x04;\n}\nif (!hasZipMagic(data)) {\n    throw new IOException(\"Expected ZIP (PK), got \" + describeMagic(data));\n}\nSkillUtils.validateZipBytes(data);","typeGuard":"static boolean isZipFormat(byte[] data) {\n    return data != null && data.length >= 4\n        && data[0] == 0x50 && data[1] == 0x4B\n        && data[2] == 0x03 && data[3] == 0x04;\n}","tryCatchPattern":"try {\n    SkillUtils.validateZipBytes(data);\n} catch (IllegalArgumentException e) {\n    log.error(\"Not a ZIP. First bytes: {}\", HexFormat.of().formatHex(Arrays.copyOf(data, 8)));\n    throw e;\n}","preventionTips":["Log the first 8 bytes in hex when magic-check fails to identify the real format.","Ensure the producer writes a standard ZIP, not gzip/tar.","Guard against CDN/proxy error pages returned with HTTP 200 — check Content-Type."],"tags":["java","nacos","ai","skills","zip","validation"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}