{"record":{"id":"b18c24ff281ec589","repo":"iflytek/astron-agent","slug":"artifact-upload-failed-error","errorCode":null,"errorMessage":"ARTIFACT_UPLOAD_FAILED_ERROR","messagePattern":"ARTIFACT_UPLOAD_FAILED_ERROR","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"core/workflow/engine/nodes/code/executor/e2b/e2b_executor.py","lineNumber":794,"sourceCode":"                    headers=headers,\n                    allow_redirects=False,\n                ) as response:\n                    if not 200 <= response.status < 300:\n                        raise ValueError\n                    response.raise_for_status()\n                    payload = await response.json(content_type=None)\n            code = payload.get(\"code\") if isinstance(payload, dict) else None\n            data = payload.get(\"data\") if isinstance(payload, dict) else None\n            if (\n                isinstance(code, bool)\n                or not isinstance(code, int)\n                or code != 0\n                or not isinstance(data, dict)\n            ):\n                raise ValueError\n            return data\n        except Exception:\n            raise RuntimeError(ARTIFACT_UPLOAD_FAILED_ERROR) from None\n","sourceCodeStart":776,"sourceCodeEnd":795,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/workflow/engine/nodes/code/executor/e2b/e2b_executor.py#L776-L795","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify SKILL_SANDBOX_ARTIFACT_UPLOAD_URL is reachable and returns the expected {code:0, data:{...}} envelope (curl the endpoint).","Check SKILL_SANDBOX_ARTIFACT_UPLOAD_TOKEN (or *_FILE) is set and >= 32 characters; confirm it is accepted (no 401/403).","Confirm the file is under 20MB and total uploads under 100MB for the run; skip or split oversized artifacts.","Retry transient network failures; check server logs for the business error code returned in the payload."],"exampleFix":"// before\npayload = await response.json(content_type=None)\nreturn payload  # crashes later or hides business errors\n// after\nif not 200 <= response.status < 300:\n    logger.warning(\"artifact upload http status={}\", response.status)\n    raise RuntimeError(ARTIFACT_UPLOAD_FAILED_ERROR)\npayload = await response.json(content_type=None)\nif not (isinstance(payload, dict) and payload.get(\"code\") == 0):\n    raise RuntimeError(ARTIFACT_UPLOAD_FAILED_ERROR)\nreturn payload[\"data\"]","handlingStrategy":"retry","validationCode":"uploader = CodeArtifactUploader(sandbox_config)\nif not uploader.is_configured():\n    # skip artifact upload instead of failing the run\n    return","typeGuard":"def is_valid_upload_payload(p: object) -> bool:\n    return (isinstance(p, dict) and isinstance(p.get(\"code\"), int)\n            and not isinstance(p.get(\"code\"), bool) and p[\"code\"] == 0\n            and isinstance(p.get(\"data\"), dict))","tryCatchPattern":"try:\n    await uploader.upload(name, data, ctype)\nexcept RuntimeError:\n    artifact[\"upload_error\"] = \"artifact_upload_failed\"  # degrade gracefully","preventionTips":["Check is_configured() before attempting uploads.","Enforce the 20MB per-file / 100MB total limits client-side before upload.","Verify upload URL and token env vars in deployment checks."],"tags":["upload","http","artifacts","validation"],"backgroundTag":"http-error-response","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}