{"record":{"id":"653bef9f8156ad52","repo":"agentscope-ai/agentscope","slug":"the-manifest-lists-len-entries-files-but-file","errorCode":null,"errorMessage":"The manifest lists {len(entries)} files but {file_count} were sent.","messagePattern":"The manifest lists (.+?) files but (.+?) were sent\\.","errorType":"exception","errorClass":"SkillUploadError","httpStatus":null,"severity":"error","filePath":"src/agentscope/app/_service/_workspace.py","lineNumber":370,"sourceCode":"        \"\"\"Check a manifest and return the skill's root directory name.\n\n        Args:\n            manifest (`UploadManifest`): The declared upload contents.\n            file_count (`int`): How many parts actually arrived.\n\n        Returns:\n            `str`: The single top-level directory every path sits under.\n\n        Raises:\n            SkillUploadError: If a limit is exceeded, a path is unsafe,\n                the paths span more than one root, no ``SKILL.md`` is\n                present, or the parts do not match the manifest.\n        \"\"\"\n        entries = manifest.entries\n        if not entries:\n            raise SkillUploadError(\"The upload contains no files.\")\n        if file_count != len(entries):\n            raise SkillUploadError(\n                f\"The manifest lists {len(entries)} files but \"\n                f\"{file_count} were sent.\",\n            )\n        if len(entries) > MAX_FILE_COUNT:\n            raise SkillUploadError(\n                f\"A skill may hold at most {MAX_FILE_COUNT} files, \"\n                f\"got {len(entries)}.\",\n            )\n\n        total = 0\n        roots: set[str] = set()\n        for entry in entries:\n            if entry.size > MAX_FILE_BYTES:\n                raise SkillUploadError(\n                    f\"{entry.path!r} is {entry.size} bytes, over the \"\n                    f\"{MAX_FILE_BYTES}-byte per-file limit.\",\n                )\n            total += entry.size","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/app/_service/_workspace.py#L352-L388","documentation":"SkillUploadError raised when the number of file parts actually streamed does not equal len(manifest.entries). The manifest is the client's declaration of the folder's contents; the server counts the multipart files it receives and refuses to proceed when the two disagree, because a partial upload would silently drop files.","triggerScenarios":"Calling upload_skill where the multipart form sends more or fewer files than the manifest declares — e.g. the manifest was built before files changed on disk, duplicate/missing form parts, or client code that appends SKILL.md to the manifest but forgets to append the corresponding file part (or vice versa).","commonSituations":"Files added/deleted between manifest generation and upload; a retry that reuses a stale manifest; bugs in client code mapping directory entries to multipart parts; double-appending an entry.","solutions":["Regenerate the manifest immediately before sending so entries and parts come from the same directory snapshot.","Verify each manifest entry has exactly one matching file part (same relative path) in the multipart body.","Remove duplicate or phantom entries introduced by client-side filtering bugs."],"exampleFix":"# before\nentries = [UploadEntry(path=f\"{root}/{p}\", size=...) for p in old_list]\nawait service.upload_skill(ws, UploadManifest(entries=entries), stream)\n\n# after\nfiles = sorted(root_dir.rglob(\"*\"))\nentries = [UploadEntry(path=str(f.relative_to(root_dir.parent)), size=f.stat().st_size) for f in files if f.is_file()]\nawait service.upload_skill(ws, UploadManifest(entries=entries), stream)","handlingStrategy":"validation","validationCode":"parts = {p.filename for p in multipart_files}\ndeclared = {e.path for e in manifest.entries}\nassert parts == declared, (parts - declared, declared - parts)","typeGuard":null,"tryCatchPattern":"try:\n    await service.upload_skill(ws, manifest, stream)\nexcept SkillUploadError as e:\n    if \"were sent\" in str(e):\n        # regenerate manifest and retry once\n        ...","preventionTips":["Generate the manifest and the file parts in one pass over the same directory snapshot.","Never reuse a manifest from a previous attempt after files changed."],"tags":["upload","manifest-mismatch","multipart","validation"],"backgroundTag":"request-validation-failed","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}