{"record":{"id":"86c2ffe8f8ec9000","repo":"conductor-oss/conductor","slug":"skill-package-exceeds-max-uncompressed-size-of-ma","errorCode":null,"errorMessage":"Skill package exceeds max uncompressed size of {maxUncompressedBytes} bytes","messagePattern":"Skill package exceeds max uncompressed size of (.+?) bytes","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java","lineNumber":460,"sourceCode":"                    throw new IllegalArgumentException(\n                            \"Skill package contains duplicate path: \" + path);\n                }\n                MessageDigest digest = MessageDigest.getInstance(\"SHA-256\");\n                long size = 0;\n                ByteArrayOutputStream content = new ByteArrayOutputStream();\n                byte[] buffer = new byte[8192];\n                int read;\n                while ((read = zip.read(buffer)) >= 0) {\n                    digest.update(buffer, 0, read);\n                    content.write(buffer, 0, read);\n                    size += read;\n                    totalUncompressedBytes += read;\n                    if (size > maxPackageBytes) {\n                        throw new IllegalArgumentException(\n                                \"Skill package contains oversized file: \" + path);\n                    }\n                    if (totalUncompressedBytes > maxUncompressedBytes) {\n                        throw new IllegalArgumentException(\n                                \"Skill package exceeds max uncompressed size of \"\n                                        + maxUncompressedBytes\n                                        + \" bytes\");\n                    }\n                }\n                contentByPath.put(path, content.toByteArray());\n                files.add(\n                        SkillFileEntry.builder()\n                                .path(path)\n                                .size(size)\n                                .sha256(hex(digest.digest()))\n                                .contentType(contentType(path))\n                                .build());\n            }\n        } catch (IllegalArgumentException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new IllegalArgumentException(\"Invalid skill package zip: \" + e.getMessage(), e);","sourceCodeStart":442,"sourceCodeEnd":478,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java#L442-L478","documentation":"Thrown by parseSkillPackage when the cumulative uncompressed size across all entries exceeds maxUncompressedBytes (default 209,715,200 = 200 MiB, configurable via agentspan.skills.max-uncompressed-bytes). This is the zip-bomb defense: it sums bytes during streaming decompression and aborts when the total crosses the cap, regardless of how small the compressed input is.","triggerScenarios":"POST /api/skills/register with a zip bomb — a tiny compressed file that decompresses to hundreds of MiB — or a legitimately large package whose combined uncompressed content exceeds 200 MiB. Checked incrementally so it trips mid-decompression.","commonSituations":"An adversarial or accidentally nested zip; bundling many large assets; lowering max-uncompressed-bytes in a shared config; vendoring a large dependency tree uncompressed.","solutions":["Reduce the total uncompressed content of the package below the limit.","Raise agentspan.skills.max-uncompressed-bytes if the large total is intentional and trusted.","Scan uploaded packages for zip bombs before they reach this service if untrusted uploads are accepted."],"exampleFix":"# application.yml\nagentspan:\n  skills:\n    max-uncompressed-bytes: 524288000  # 500 MiB","handlingStrategy":"validation","validationCode":"// Before zipping, sum uncompressed sizes of all included files\nlong total = includedFiles.stream().mapToLong(p -> { try { return Files.size(p); } catch (IOException e) { return 0; } }).sum();\nif (total > maxUncompressedBytes) throw new IllegalArgumentException(\"uncompressed total too large: \" + total);","typeGuard":"static boolean withinUncompressedTotal(long total, long maxUncompressedBytes) { return total <= maxUncompressedBytes; }","tryCatchPattern":"try { skillRegistryService.register(manifest, pkg); }\ncatch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"max uncompressed size\")) { /* reduce content or raise limit */ }\n    else throw e;\n}","preventionTips":["Treat any untrusted upload as a potential zip bomb and pre-scan total uncompressed size.","Keep skill packages lean; host bulky assets externally."],"tags":["java","conductor","skill-registry","size-limit","zip-bomb","security","zip"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}