OpenBMB/ChatDev · error · HTTPException
Artifact stream not available
Error message
Artifact stream not available
What it means
The session exists but session.artifact_queue is None, meaning no artifact event stream was ever attached to it. The helper returns 404 because there is nothing to poll or stream from this session.
Solutions
- Establish the websocket connection for the session first so the artifact queue is created
- Run a workflow that produces artifacts before polling
- Reconnect the session if the queue was torn down after disconnect
- Confirm you're using the same server instance that owns the session
Defensive patterns
Strategy: validation
Validate before calling
# only poll after the session reports a websocket connection / artifacts exist
if not session_has_artifacts(session_id):
return # skip polling Try / catch
if resp.status_code == 404 and resp.json()['detail'] == 'Artifact stream not available':
connect_websocket(session_id) # initialize the queue, then retry Prevention
- Open the session websocket before polling artifact events
- Don't poll sessions whose runs never produced artifacts
When it happens
Trigger: Calling artifact endpoints on a session whose websocket connection never initialized the artifact queue, or after the queue was torn down at session close.
Common situations: Polling artifact events on a session that completed without ever connecting a websocket client, or after the session's streaming lifecycle ended.
Related errors
- Session not found
- Artifact content unavailable
- Artifact file missing
- Artifact not found
- Session directory not found
AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27).
Data as JSON: /api/errors/c5cfbba84ae4fc5a.
Report an issue: GitHub.
Appendix: source
Thrown at server/routes/artifacts.py:31
MAX_FILE_SIZE = 20 * 1024 * 1024 # 20 MB
def _split_csv(value: Optional[str]) -> Optional[List[str]]:
if not value:
return None
parts = [part.strip() for part in value.split(",")]
filtered = [part for part in parts if part]
return filtered or None
def _get_session_and_queue(session_id: str):
manager = get_websocket_manager()
session = manager.session_store.get_session(session_id)
if not session:
raise HTTPException(status_code=404, detail="Session not found")
queue = session.artifact_queue
if queue is None:
raise HTTPException(status_code=404, detail="Artifact stream not available")
return manager, queue
@router.get("/api/sessions/{session_id}/artifact-events")
async def poll_artifact_events(
session_id: str,
wait_seconds: float = Query(25.0, ge=0.0, le=60.0),
after: Optional[int] = Query(None, ge=0),
include_mime: Optional[str] = Query(None),
include_ext: Optional[str] = Query(None),
max_size: Optional[int] = Query(None, gt=0),
limit: int = Query(25, ge=1, le=100),
):
manager, queue = _get_session_and_queue(session_id)
include_mime_list = _split_csv(include_mime)
include_ext_list = _split_csv(include_ext)
events, next_cursor, timed_out = await asyncio.to_thread(View on GitHub (pinned to 4fb2db0ea9)