alibaba/nacos · error · IllegalArgumentException
Invalid ZIP data: missing ZIP magic header (PK\x03\x04)
Error message
Invalid ZIP data: missing ZIP magic header (PK\x03\x04)
What it means
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.
Source
Thrown at api/src/main/java/com/alibaba/nacos/api/ai/model/skills/SkillUtils.java:207
throw new SecurityException(
"Path escapes target directory: " + target + " is outside " + baseDir);
}
}
/**
* Validate that byte array is a valid ZIP file by checking the magic number header.
*
* @param data the byte array to validate
* @throws IllegalArgumentException if data is null, too short, or does not have ZIP magic header
*/
public static void validateZipBytes(byte[] data) {
if (data == null || data.length < ZIP_MIN_SIZE) {
throw new IllegalArgumentException(
"Invalid ZIP data: too short (" + (data == null ? 0 : data.length) + " bytes)");
}
for (int i = 0; i < ZIP_MAGIC.length; i++) {
if (data[i] != ZIP_MAGIC[i]) {
throw new IllegalArgumentException(
"Invalid ZIP data: missing ZIP magic header (PK\\x03\\x04)");
}
}
}
/**
* Validate all ZIP entry paths for path traversal and absolute paths.
*
* <p>Scans entry names only without decompressing content, so it is lightweight
* and suitable for validating downloaded ZIP bytes on the client side.</p>
*
* @param data the ZIP byte array to validate
* @throws SecurityException if any entry contains path traversal or absolute path
* @throws IOException if ZIP cannot be read
*/
public static void validateZipEntryPaths(byte[] data) throws IOException {
try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(data))) {
ZipEntry entry;View on GitHub (pinned to 9b989acdf1)
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.
Example fix
// before
byte[] data = "{\"error\":\"not found\"}".getBytes();
SkillUtils.validateZipBytes(data); // throws: missing magic
// after
byte[] data = SkillUtils.toZipBytes(skill); // produces valid PK ZIP
SkillUtils.validateZipBytes(data); // ok Defensive patterns
Strategy: validation
Validate before calling
static boolean hasZipMagic(byte[] data) {
return data != null && data.length >= 4
&& (data[0] & 0xFF) == 0x50 && (data[1] & 0xFF) == 0x4B
&& (data[2] & 0xFF) == 0x03 && (data[3] & 0xFF) == 0x04;
}
if (!hasZipMagic(data)) {
throw new IOException("Expected ZIP (PK), got " + describeMagic(data));
}
SkillUtils.validateZipBytes(data); Type guard
static boolean isZipFormat(byte[] data) {
return data != null && data.length >= 4
&& data[0] == 0x50 && data[1] == 0x4B
&& data[2] == 0x03 && data[3] == 0x04;
} Try / catch
try {
SkillUtils.validateZipBytes(data);
} catch (IllegalArgumentException e) {
log.error("Not a ZIP. First bytes: {}", HexFormat.of().formatHex(Arrays.copyOf(data, 8)));
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid ZIP data: too short ({length} bytes)
- Absolute path not allowed: {path}
- Base directory cannot be blank
- Skill directory name cannot be blank
- Skill directory already exists: {skillDir}
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/18ce8f7e9c67dbb1.
Report an issue: GitHub.