{"record":{"id":"dab80002a0c12aa2","repo":"agentscope-ai/agentscope","slug":"entry-path-r-is-larger-than-its-declared-entry","errorCode":null,"errorMessage":"{entry.path!r} is larger than its declared {entry.size} bytes.","messagePattern":"(.+?) is larger than its declared (.+?) bytes\\.","errorType":"validation","errorClass":"SkillUploadError","httpStatus":null,"severity":"error","filePath":"src/agentscope/app/_service/_workspace.py","lineNumber":471,"sourceCode":"\n        Yields:\n            `bytes`: The next chunk of the tar archive.\n\n        Raises:\n            SkillUploadError: If a part's real length differs from its\n                declared size.\n        \"\"\"\n        for entry, upload in zip(manifest.entries, files):\n            info = tarfile.TarInfo(name=entry.path)\n            info.size = entry.size\n            info.mtime = 0\n            yield info.tobuf(tarfile.GNU_FORMAT)\n\n            written = 0\n            while chunk := await upload.read(_CHUNK_SIZE):\n                written += len(chunk)\n                if written > entry.size:\n                    raise SkillUploadError(\n                        f\"{entry.path!r} is larger than its declared \"\n                        f\"{entry.size} bytes.\",\n                    )\n                yield chunk\n\n            if written != entry.size:\n                raise SkillUploadError(\n                    f\"{entry.path!r} declared {entry.size} bytes but \"\n                    f\"sent {written}.\",\n                )\n            padding = -entry.size % _TAR_BLOCK\n            if padding:\n                yield b\"\\0\" * padding\n\n        # Two zero blocks mark the end of a tar archive.\n        yield b\"\\0\" * (2 * _TAR_BLOCK)\n\n    # ── Git status ─────────────────────────────────────────────────────","sourceCodeStart":453,"sourceCodeEnd":489,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/app/_service/_workspace.py#L453-L489","documentation":"Raised by tar_stream in the workspace service when the bytes actually read from the upload stream for a file exceed the size declared in the manifest (TarInfo) for that entry. It is a SkillUploadError that aborts a streaming skill upload because the tar payload would be malformed (the tar header would no longer match the file data). It protects the server from writing corrupt archives.","triggerScenarios":"Calling upload_skill (or otherwise consuming tar_stream) where a manifest entry declares entry.size smaller than the real byte length of the corresponding file. Happens when the file changes on disk between manifest creation and streaming, or when the manifest is built with stale/wrong sizes (e.g. stat before truncation, off-by-one size computation, or reusing a manifest across uploads).","commonSituations":"Skill directory being mutated concurrently (logs written during upload), generating the manifest from metadata that doesn't match the actual file, unit tests that declare a smaller size than the payload they feed (test_declared_size_is_verified).","solutions":["Recompute the manifest entry sizes immediately before uploading so entry.size matches the actual file length","Ensure the skill directory is not being written to (close logs, stop generators) during the upload","If files change frequently, snapshot/copy the skill directory to a temp location and build both manifest and stream from the snapshot","In tests, assert your fixture's declared size equals len(payload) before calling upload_skill"],"exampleFix":"# before\ninfo.size = 100  # hardcoded / stale\ninfo = _tar_info(entry, size=100)\n\n# after\nsize = entry_path.stat().st_size  # measured right before streaming\ninfo = _tar_info(entry, size=size)","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef check_sizes(base: Path, entries) -> None:\n    for e in entries:\n        actual = (base / e.path).stat().st_size\n        if actual != e.size:\n            raise RuntimeError(f\"{e.path}: manifest says {e.size}, disk has {actual}; rebuild manifest\")","typeGuard":null,"tryCatchPattern":"try:\n    await upload_skill(...)\nexcept SkillUploadError as e:\n    if \"larger than its declared\" in str(e):\n        rebuild_manifest_and_retry()  # sizes drifted; recompute and re-upload","preventionTips":["Build the manifest and the byte stream from the same snapshot of the directory","Freeze/lock skill directories (no concurrent writers) during upload","In tests, assert declared size == len(payload) before invoking upload_skill"],"tags":["tar","streaming","upload-validation","skill-upload"],"backgroundTag":"stream-size-mismatch","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}