agentscope-ai/agentscope · error · RuntimeError

Failed to expand skill archive: {result.stderr.decode('utf-8

Error message

Failed to expand skill archive: {result.stderr.decode('utf-8', 'replace')}

What it means

Raised by add_skill_archive when the subprocess used to extract the uploaded archive (into a staging directory, with a byte cap) exits non-zero. The RuntimeError wraps the extractor's stderr, so the message tells you why unpacking failed: unsupported format, corrupt archive, or extraction size limit exceeded.

Source

Thrown at src/agentscope/workspace/_local_workspace.py:923

            self.workdir,
            f".skill-staging-{_generate_id()}",
        )
        archive_path = f"{staging}.{'tar.gz' if fmt == 'tar.gz' else fmt}"
        try:
            await self._backend.write_stream(archive_path, stream)
            result = await self._backend.exec_shell(
                [
                    self._python_command,
                    "-c",
                    _EXTRACT_ARCHIVE_SHIM,
                    archive_path,
                    staging,
                    fmt,
                    str(max_extracted_bytes),
                ],
            )
            if not result.ok():
                raise RuntimeError(
                    f"Failed to expand skill archive: "
                    f"{result.stderr.decode('utf-8', 'replace')}",
                )
            await self.add_skill(
                await self._find_skill_root(staging),
                agent_id=agent_id,
            )
        finally:
            await self._backend.delete_path(staging)
            await self._backend.delete_path(archive_path)

    async def remove_skill(
        self,
        name: str,
        *,
        agent_id: str | None = None,
    ) -> None:
        """Remove a skill from the workspace by its agent-facing name.

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Re-create the archive with a standard format matching fmt (e.g. tar czf skill.tar.gz skill-dir) and retry.
  2. Read result.stderr in the exception message to identify the exact extractor failure (format vs size limit).
  3. If the archive is legitimately large, raise max_extracted_bytes when calling add_skill_archive.
  4. Verify archive integrity locally (tar -tzf skill.tar.gz / unzip -t skill.zip) before uploading.

Example fix

# before
await ws.add_skill_archive(data, fmt="tar.gz")  # stderr: 'unsupported format'

# after
import tarfile, io
buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode="w:gz") as tf:
    tf.add("my-skill")
await ws.add_skill_archive(buf.getvalue(), fmt="tar.gz")
Defensive patterns

Strategy: try-catch

Validate before calling

import tarfile, zipfile

def archive_is_sound(data: bytes, fmt: str) -> bool:
    import io
    if fmt == "zip":
        return zipfile.ZipFile(io.BytesIO(data)).testzip() is None
    with tarfile.open(fileobj=io.BytesIO(data), mode="r:*") as tf:
        return len(tf.getnames()) > 0

Try / catch

try:
    await ws.add_skill_archive(data, fmt=fmt)
except RuntimeError as e:
    if "Failed to expand skill archive" in str(e):
        raise SkillArchiveError(str(e)) from e
    raise

Prevention

When it happens

Trigger: Calling add_skill_archive with a corrupt/truncated archive, an archive format not supported by the extractor (fmt mismatch), or an archive whose extracted contents exceed max_extracted_bytes (deflate bombs / large skills).

Common situations: Uploading .zip files renamed to .tar.gz, archives created with exotic compression (e.g. zstd) unsupported by the extractor, truncated uploads, or hitting the configured extraction byte limit with large model files inside the skill.

Related errors


AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28). Data as JSON: /api/errors/562560c0be481fa7. Report an issue: GitHub.