diff --git a/backend/open_webui/retrieval/loaders/mistral.py b/backend/open_webui/retrieval/loaders/mistral.py index 465ea5d91e..5e30160c47 100644 --- a/backend/open_webui/retrieval/loaders/mistral.py +++ b/backend/open_webui/retrieval/loaders/mistral.py @@ -261,33 +261,32 @@ class MistralLoader: url = f'{self.base_url}/files' async def upload_request(): - # Create multipart writer for streaming upload - writer = aiohttp.MultipartWriter('form-data') + # Open inside the request so the handle stays valid for the whole + # streamed POST and is closed right after. + with open(self.file_path, 'rb') as f: + writer = aiohttp.MultipartWriter('form-data') - # Add purpose field - purpose_part = writer.append('ocr') - purpose_part.set_content_disposition('form-data', name='purpose') + # Add purpose field + purpose_part = writer.append('ocr') + purpose_part.set_content_disposition('form-data', name='purpose') - # Add file part with streaming - file_part = writer.append_payload( - aiohttp.streams.FilePayload( - self.file_path, - filename=self.file_name, - content_type='application/pdf', - ) - ) - file_part.set_content_disposition('form-data', name='file', filename=self.file_name) + # Stream the file. aiohttp builds a payload from the file object; + # the previous aiohttp.streams.FilePayload was removed upstream + # (payloads live in aiohttp.payload and there is no FilePayload), + # so this path raised AttributeError on every async OCR upload. + file_part = writer.append(f, {'Content-Type': 'application/pdf'}) + file_part.set_content_disposition('form-data', name='file', filename=self.file_name) - self._debug_log(f'Uploading file: {self.file_name} ({self.file_size:,} bytes)') + self._debug_log(f'Uploading file: {self.file_name} ({self.file_size:,} bytes)') - async with session.post( - url, - data=writer, - headers=self.headers, - timeout=aiohttp.ClientTimeout(total=self.upload_timeout), - ssl=AIOHTTP_CLIENT_SESSION_SSL, - ) as response: - return await self._handle_response_async(response) + async with session.post( + url, + data=writer, + headers=self.headers, + timeout=aiohttp.ClientTimeout(total=self.upload_timeout), + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as response: + return await self._handle_response_async(response) response_data = await self._retry_request_async(upload_request)