iflytek/astron-agent · warning · RuntimeError

ARTIFACT_UPLOAD_FAILED_ERROR

Error message

ARTIFACT_UPLOAD_FAILED_ERROR

What it means

CodeArtifactUploader.upload() posts an artifact file to the internal upload endpoint and strictly validates the result: HTTP status must be 2xx AND the JSON payload must be a dict with an integer code == 0 and a dict 'data'. Any deviation (non-2xx, redirect, non-JSON body, business error code, malformed payload) raises RuntimeError('artifact_upload_failed'). Callers (_upload_artifact) catch this and mark the artifact's upload_error field.

Solutions

  1. Verify SKILL_SANDBOX_ARTIFACT_UPLOAD_URL is reachable and returns the expected {code:0, data:{...}} envelope (curl the endpoint).
  2. Check SKILL_SANDBOX_ARTIFACT_UPLOAD_TOKEN (or *_FILE) is set and >= 32 characters; confirm it is accepted (no 401/403).
  3. Confirm the file is under 20MB and total uploads under 100MB for the run; skip or split oversized artifacts.
  4. Retry transient network failures; check server logs for the business error code returned in the payload.

Example fix

// before
payload = await response.json(content_type=None)
return payload  # crashes later or hides business errors
// after
if not 200 <= response.status < 300:
    logger.warning("artifact upload http status={}", response.status)
    raise RuntimeError(ARTIFACT_UPLOAD_FAILED_ERROR)
payload = await response.json(content_type=None)
if not (isinstance(payload, dict) and payload.get("code") == 0):
    raise RuntimeError(ARTIFACT_UPLOAD_FAILED_ERROR)
return payload["data"]
Defensive patterns

Strategy: retry

Validate before calling

uploader = CodeArtifactUploader(sandbox_config)
if not uploader.is_configured():
    # skip artifact upload instead of failing the run
    return

Type guard

def is_valid_upload_payload(p: object) -> bool:
    return (isinstance(p, dict) and isinstance(p.get("code"), int)
            and not isinstance(p.get("code"), bool) and p["code"] == 0
            and isinstance(p.get("data"), dict))

Try / catch

try:
    await uploader.upload(name, data, ctype)
except RuntimeError:
    artifact["upload_error"] = "artifact_upload_failed"  # degrade gracefully

Prevention

When it happens

Trigger: Upload POST returns non-2xx status or redirects; response body is not JSON; payload.code != 0 or code is a bool/missing; payload.data is missing or not a dict; aiohttp network/timeout error during the 60s-limited request.

Common situations: Wrong SKILL_SANDBOX_ARTIFACT_UPLOAD_URL or service down; artifact upload token missing/shorter than 32 chars causing 401/403; file exceeds 20MB per-file or 100MB total limits rejected by server; transient network failure.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at core/workflow/engine/nodes/code/executor/e2b/e2b_executor.py:794

                    headers=headers,
                    allow_redirects=False,
                ) as response:
                    if not 200 <= response.status < 300:
                        raise ValueError
                    response.raise_for_status()
                    payload = await response.json(content_type=None)
            code = payload.get("code") if isinstance(payload, dict) else None
            data = payload.get("data") if isinstance(payload, dict) else None
            if (
                isinstance(code, bool)
                or not isinstance(code, int)
                or code != 0
                or not isinstance(data, dict)
            ):
                raise ValueError
            return data
        except Exception:
            raise RuntimeError(ARTIFACT_UPLOAD_FAILED_ERROR) from None

View on GitHub (pinned to 5e758547a8)