{"record":{"id":"d56db253a19ca322","repo":"open-webui/open-webui","slug":"mineru-cloud-api-response-missing-batch-id-or-file","errorCode":null,"errorMessage":"MinerU Cloud API response missing batch_id or file_urls","messagePattern":"MinerU Cloud API response missing batch_id or file_urls","errorType":"http","errorClass":"HTTPException","httpStatus":502,"severity":"error","filePath":"backend/open_webui/retrieval/loaders/mineru.py","lineNumber":281,"sourceCode":"        except ValueError as e:\n            raise HTTPException(\n                status.HTTP_502_BAD_GATEWAY,\n                detail=f'Invalid JSON response: {e}',\n            )\n\n        # Check for API error response\n        if result.get('code') != 0:\n            raise HTTPException(\n                status.HTTP_400_BAD_REQUEST,\n                detail=f'MinerU Cloud API error: {result.get(\"msg\", \"Unknown error\")}',\n            )\n\n        data = result.get('data', {})\n        batch_id = data.get('batch_id')\n        file_urls = data.get('file_urls', [])\n\n        if not batch_id or not file_urls:\n            raise HTTPException(\n                status.HTTP_502_BAD_GATEWAY,\n                detail='MinerU Cloud API response missing batch_id or file_urls',\n            )\n\n        upload_url = file_urls[0]\n        log.info(f'Received upload URL for batch: {batch_id}')\n\n        return batch_id, upload_url\n\n    def _upload_to_presigned_url(self, upload_url: str) -> None:\n        \"\"\"\n        Upload file to presigned URL (no authentication needed).\n        \"\"\"\n        log.info(f'Uploading file to presigned URL')\n\n        try:\n            with open(self.file_path, 'rb') as f:\n                response = requests.put(","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/open-webui/open-webui/blob/01f4282f1ffe0d6212f58d3afbeae21fffd0c4be/backend/open_webui/retrieval/loaders/mineru.py#L263-L299","documentation":"Raised as HTTP 502 when the /file-urls/batch JSON has code == 0 but data lacks batch_id or file_urls (or they are empty). The cloud API claimed success yet omitted the fields required for steps 2-3 (upload and polling), so the response shape does not match what this loader expects.","triggerScenarios":"API version change renaming data fields (e.g. batch_id -> id); an empty file_urls list because the request body's files array was dropped/emptied by a proxy or serialization issue; an A/B schema on the server side.","commonSituations":"MinerU cloud contract change after an api_url version bump; params containing a 'files' key that shadows the loader's own files field via {**self.params}; middlewares stripping parts of the JSON body.","solutions":["Log the full response JSON and diff its data keys against batch_id/file_urls","Ensure params does not contain a 'files' key - it would be overridden, but other collisions may leak in","Pin api_url to the API version this loader targets","Check for a 'files' entry mismatch (name/is_ocr fields) in the request"],"exampleFix":"// before\nparams = {'files': [{'name': 'x.pdf'}], 'language': 'en'}  # collides with loader body\nloader = MinerULoader(file_path=p, api_mode='cloud', api_key=key, params=params)\n\n// after\nparams = {'language': 'en'}\nloader = MinerULoader(file_path=p, api_mode='cloud', api_key=key, params=params)","handlingStrategy":"type-guard","validationCode":"# Prevent the most common trigger: params keys colliding with the request body\nassert 'files' not in (params or {}), \"params must not contain 'files'\"","typeGuard":"def is_upload_url_response(obj) -> bool:\n    if not (isinstance(obj, dict) and obj.get('code') == 0):\n        return False\n    data = obj.get('data') or {}\n    return (\n        isinstance(data.get('batch_id'), str)\n        and bool(data['batch_id'])\n        and isinstance(data.get('file_urls'), list)\n        and len(data['file_urls']) > 0\n        and isinstance(data['file_urls'][0], str)\n    )","tryCatchPattern":"try:\n    docs = loader.load()\nexcept HTTPException as e:\n    if e.status_code == 502 and 'missing batch_id or file_urls' in e.detail:\n        log.error('Cloud schema change suspected - capture raw response')\n    raise","preventionTips":["Never put a 'files' key into params","Pin api_url to the tested API version","Log raw cloud responses at debug level to diagnose schema drift fast"],"tags":["mineru","cloud-api","schema","bad-gateway","version-mismatch"],"backgroundTag":null,"analyzedSha":"01f4282f1ffe0d6212f58d3afbeae21fffd0c4be","analyzedAt":"2026-08-14T18:25:22.715Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}