OpenBMB/ChatDev · error · HTTPException

Artifact content unavailable

Error message

Artifact content unavailable

What it means

The artifact record exists but its ref.local_path is None, so the server cannot stream the file content. This happens for artifacts stored inline (data URI) rather than on disk, while the request used mode=stream.

Source

Thrown at server/routes/artifacts.py:85

@router.get("/api/sessions/{session_id}/artifacts/{artifact_id}")
async def get_artifact(
    session_id: str,
    artifact_id: str,
    mode: str = Query("meta", pattern="^(meta|stream)$"),
    download: bool = Query(False),
):
    manager, _ = _get_session_and_queue(session_id)
    store = manager.attachment_service.get_attachment_store(session_id)
    record = store.get(artifact_id)
    if not record:
        raise HTTPException(status_code=404, detail="Artifact not found")

    ref = record.ref
    if mode == "stream":
        local_path = ref.local_path
        if not local_path:
            raise HTTPException(status_code=404, detail="Artifact content unavailable")
        path = Path(local_path)
        if not path.exists():
            raise HTTPException(status_code=404, detail="Artifact file missing")
        media_type = ref.mime_type or "application/octet-stream"
        disposition = "attachment" if download else "inline"
        headers = {"Content-Disposition": f'{disposition}; filename="{ref.name}"'}
        return StreamingResponse(path.open("rb"), media_type=media_type, headers=headers)

    data_uri = ref.data_uri
    if not data_uri and ref.local_path and (ref.size or 0) <= MAX_FILE_SIZE:
        local_path = Path(ref.local_path)
        if local_path.exists():
            data_uri = encode_file_to_data_uri(local_path, ref.mime_type or "application/octet-stream")
    return {
        "artifact_id": artifact_id,
        "name": ref.name,
        "mime_type": ref.mime_type,
        "size": ref.size,

View on GitHub (pinned to 4fb2db0ea9)

Solutions

  1. Omit mode or use the default mode so the data_uri branch is used for inline artifacts
  2. Check the artifact event payload for whether the artifact is inline before choosing mode=stream
  3. If streaming is required, configure the attachment store to always persist artifacts to disk

Example fix

# before
GET /api/sessions/{sid}/artifacts/{aid}?mode=stream
# after
GET /api/sessions/{sid}/artifacts/{aid}  # falls back to data_uri
Defensive patterns

Strategy: fallback

Validate before calling

ref = client.get_artifact_meta(session_id, artifact_id)
mode = 'stream' if ref.get('local_path') else None

Type guard

def is_streamable(ref) -> bool:
    return bool(ref.get('local_path'))

Try / catch

try:
    data = client.get_artifact(sid, aid, mode='stream')
except HTTPError as e:
    if e.response.status_code == 404:  # content unavailable
        data = client.get_artifact(sid, aid)  # data_uri fallback

Prevention

When it happens

Trigger: GET .../artifacts/{id}?mode=stream for an inline/small artifact whose reference carries a data_uri instead of a local_path.

Common situations: Artifacts below the size threshold get inlined as data URIs; a client hardcodes mode=stream for all downloads.

Related errors


AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27). Data as JSON: /api/errors/7071183a38e60866. Report an issue: GitHub.