iflytek/astron-agent · error · RuntimeError

artifact_snapshot_failed

Error message

artifact_snapshot_failed

What it means

Raised in _scan_artifact_candidates when the artifact-scan helper script executed inside the E2B sandbox exits with a non-zero exit code. The helper walks the output directory collecting candidate artifact files; a non-zero exit means the scan could not complete reliably, so artifact collection aborts with 'artifact_snapshot_failed'.

Solutions

  1. Inspect the sandbox command result (stderr may be suppressed by 2>/dev/null) — rerun the scan command manually inside the sandbox without suppression to see the real error.
  2. Verify python3 exists in the sandbox image at /usr/local/bin:/usr/bin:/bin and install it in the image if absent.
  3. Increase the command timeout passed to _collect_artifacts if large output directories cause timeouts.
  4. Retry the sandbox run; transient sandbox state (e.g. killed process) often resolves on a fresh execution.

Example fix

// before (debug)
PATH=... python3 -c '<helper>' ... 2>/dev/null | head -c N
// after (diagnose)
# run inside the sandbox without 2>/dev/null to see the helper's error output
Defensive patterns

Strategy: retry

Validate before calling

def sandbox_supports_scan(sandbox) -> bool:
    # ensure python3 exists before running helper-based commands
    r = sandbox.commands.run("command -v python3", timeout=10, user="root")
    return int(getattr(r, "exit_code", 1)) == 0

Type guard

def scan_result_ok(result) -> bool:
    return result is not None and int(getattr(result, "exit_code", 1) or 0) == 0 and bool(str(getattr(result, "stdout", "") or "").strip())

Try / catch

for attempt in range(2):
    try:
        candidates = await _scan_artifact_candidates(sandbox, output_dir, excluded, timeout_s)
        break
    except RuntimeError as e:
        if str(e) == "artifact_snapshot_failed" and attempt == 0:
            logger.warning("artifact scan failed once; retrying with fresh command")
            continue
        logger.warning("artifact collection skipped: snapshot scan failed")
        candidates = []

Prevention

When it happens

Trigger: sandbox.commands.run returns exit_code != 0 for the scan command — e.g. python3 missing or failing inside the sandbox, the helper crashing, the `head -c` pipe closing early, or command timeout causing abnormal termination.

Common situations: Sandbox image lacks python3 on PATH (command hardcodes PATH=/usr/local/bin:/usr/bin:/bin); output directory deleted mid-run; sandbox resource exhaustion; timeout_seconds too small for large output trees.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/b6224999792cc940. Report an issue: GitHub.

Appendix: source

Thrown at core/agent/service/plugin/skill_sandbox.py:333

    timeout_seconds: int,
) -> list[dict[str, Any]]:
    command = _bounded_helper_command(
        _ARTIFACT_SCAN_HELPER,
        [
            output_dir,
            str(MAX_ARTIFACT_FILES_PER_RUN + 1),
            json.dumps(sorted(excluded_paths), ensure_ascii=True),
            str(MAX_ARTIFACT_RELATIVE_PATH_BYTES),
        ],
        MAX_ARTIFACT_SCAN_OUTPUT_BYTES,
    )
    result = await sandbox.commands.run(
        command,
        timeout=timeout_seconds,
        user="root",
    )
    if int(getattr(result, "exit_code", 0) or 0) != 0:
        raise RuntimeError(ARTIFACT_SNAPSHOT_ERROR)
    stdout = str(getattr(result, "stdout", "") or "")
    if len(stdout.encode("utf-8", "surrogateescape")) > MAX_ARTIFACT_SCAN_OUTPUT_BYTES:
        raise RuntimeError(ARTIFACT_SNAPSHOT_ERROR)
    try:
        payload = json.loads(stdout)
    except (TypeError, ValueError):
        raise RuntimeError(ARTIFACT_SNAPSHOT_ERROR) from None
    if not isinstance(payload, list) or len(payload) > MAX_ARTIFACT_FILES_PER_RUN + 1:
        raise RuntimeError(ARTIFACT_SNAPSHOT_ERROR)
    return [item for item in payload if isinstance(item, dict)]


async def _read_bounded_snapshot(
    sandbox: Any,
    file_path: str,
    max_bytes: int,
    timeout_seconds: int,
) -> tuple[bytes, bool]:

View on GitHub (pinned to 5e758547a8)