{"record":{"id":"9a23da127d2ac31d","repo":"conductor-oss/conductor","slug":"skill-package-exceeds-max-file-count-of-maxfileco","errorCode":null,"errorMessage":"Skill package exceeds max file count of {maxFileCount}","messagePattern":"Skill package exceeds max file count of (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java","lineNumber":437,"sourceCode":"        } catch (IOException e) {\n            throw new IllegalArgumentException(\n                    \"Failed to read skill package: \" + e.getMessage(), e);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private ParsedSkillPackage parseSkillPackage(byte[] bytes, Map<String, Object> manifest) {\n        List<SkillFileEntry> files = new ArrayList<>();\n        Map<String, byte[]> contentByPath = new TreeMap<>();\n        long totalUncompressedBytes = 0;\n        try (ZipInputStream zip = new ZipInputStream(new ByteArrayInputStream(bytes))) {\n            ZipEntry entry;\n            while ((entry = zip.getNextEntry()) != null) {\n                if (entry.isDirectory()) {\n                    continue;\n                }\n                if (files.size() >= maxFileCount) {\n                    throw new IllegalArgumentException(\n                            \"Skill package exceeds max file count of \" + maxFileCount);\n                }\n                String path = normalizeEntryName(entry.getName());\n                if (contentByPath.containsKey(path)) {\n                    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) {","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java#L419-L455","documentation":"Thrown by parseSkillPackage when the number of non-directory entries in the zip reaches maxFileCount (default 2000, configurable via agentspan.skills.max-file-count). The check fires at the top of the per-entry loop before reading each entry's content, so it stops early once the cap is hit.","triggerScenarios":"POST /api/skills/register with a zip containing more than 2000 files — e.g. a skill that accidentally bundled node_modules, a git repo, or a generated asset tree.","commonSituations":"Running 'zip -r skill.zip .' from the wrong directory and capturing vendored deps or build output; a build step emitting thousands of small files; lowering max-file-count in config.","solutions":["Clean the package: exclude node_modules, target/, dist/, .git, and other generated trees before zipping.","Raise agentspan.skills.max-file-count if a large file count is genuinely needed.","Build the zip from an explicit allowlist of files rather than a recursive directory."],"exampleFix":"# before\nzip -r skill.zip .   # captures node_modules\n# after (explicit allowlist)\nzip skill.zip SKILL.md scripts/ references/","handlingStrategy":"validation","validationCode":"// Before zipping, count the files you intend to include\nlong count;\ntry (var z = new ZipFile(packageFile)) { count = z.stream().filter(e -> !e.isDirectory()).count(); }\nif (count > maxFileCount) { throw new IllegalArgumentException(\"too many files: \" + count); }","typeGuard":"static boolean withinFileCount(long count, int maxFileCount) { return count <= maxFileCount; }","tryCatchPattern":"try { skillRegistryService.register(manifest, pkg); }\ncatch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"exceeds max file count\")) { /* prune vendored/generated files */ }\n    else throw e;\n}","preventionTips":["Build the zip from an explicit allowlist, never a bare recursive directory.","Add a .gitignore-style exclusion for node_modules, target, dist in the packaging script."],"tags":["java","conductor","skill-registry","size-limit","zip","validation"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}