{"record":{"id":"c9d8af2ecf9c6942","repo":"sgl-project/sglang","slug":"mesh-has-been-uploaded-to-cloud-storage-please-us","errorCode":null,"errorMessage":"Mesh has been uploaded to cloud storage. Please use the cloud URL: {job.get('url')}","messagePattern":"Mesh has been uploaded to cloud storage\\. Please use the cloud URL: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"python/sglang/multimodal_gen/runtime/entrypoints/openai/mesh_api.py","lineNumber":263,"sourceCode":"@router.delete(\"/{mesh_id}\", response_model=MeshResponse)\nasync def delete_mesh(mesh_id: str = Path(...)):\n    job = await MESH_STORE.pop(mesh_id)\n    if not job:\n        raise HTTPException(status_code=404, detail=\"Mesh not found\")\n    job[\"status\"] = \"deleted\"\n    return MeshResponse(**job)\n\n\n@router.get(\"/{mesh_id}/content\")\nasync def download_mesh_content(\n    mesh_id: str = Path(...), variant: Optional[str] = Query(None)\n):\n    job = await MESH_STORE.get(mesh_id)\n    if not job:\n        raise HTTPException(status_code=404, detail=\"Mesh not found\")\n\n    if job.get(\"url\"):\n        raise HTTPException(\n            status_code=400,\n            detail=f\"Mesh has been uploaded to cloud storage. Please use the cloud URL: {job.get('url')}\",\n        )\n\n    file_path = job.get(\"file_path\")\n    if not file_path or not os.path.exists(file_path):\n        raise HTTPException(status_code=404, detail=\"Generation is still in-progress\")\n\n    ext = os.path.splitext(file_path)[1].lower()\n    media_type = {\n        \".glb\": \"model/gltf-binary\",\n        \".obj\": \"text/plain\",\n    }.get(ext, \"application/octet-stream\")\n\n    return FileResponse(\n        path=file_path, media_type=media_type, filename=os.path.basename(file_path)\n    )\n","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/entrypoints/openai/mesh_api.py#L245-L281","documentation":"The mesh artifact was uploaded to cloud storage, so local download is refused with HTTP 400 and the cloud URL is returned in the detail message. This is a redirect-by-error pattern, not a real failure.","triggerScenarios":"Calling GET /{mesh_id}/content for a job whose record contains a 'url' field (cloud upload already happened).","commonSituations":"Deployment configured to sync outputs to object storage (S3/OSS); client using an old download flow after the server enabled cloud uploads.","solutions":["Parse the cloud URL out of the 404/400 response detail and fetch from there","Check the job record via GET /{mesh_id} for the 'url' field before calling /content","Update the client to prefer job['url'] when present"],"exampleFix":"# before\ncontent = await client.get(f\"/v1/mesh/{id}/content\").content\n# after\njob = (await client.get(f\"/v1/mesh/{id}\")).json()\nif job.get(\"url\"):\n    content = await fetch(job[\"url\"])\nelse:\n    content = (await client.get(f\"/v1/mesh/{id}/content\")).content","handlingStrategy":"fallback","validationCode":"job = (await client.get(f'/v1/mesh/{id}')).json()\nurl = job.get('url')\nif url: download_from(url)  # skip /content entirely","typeGuard":null,"tryCatchPattern":"if resp.status_code == 400 and 'cloud URL' in detail:\n    url = detail.rsplit(': ', 1)[1]; fetch(url)","preventionTips":["Prefer job['url'] when present","Don't treat this 400 as a failure — it carries the real location"],"tags":["http","cloud-storage","redirect","mesh-generation"],"backgroundTag":"resource-moved-to-remote","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}