xtekky/gpt4free · error · Exception

Upload failed: {result}

Error message

Upload failed: {result}

What it means

Raised during OperaAria (V2 flow) file upload polling when the files endpoint reports upload_status of 'failed' or 'error' for the uploaded file. The provider uploads media, then polls GET {files_endpoint}{file_id} until 'finished'; a terminal failure status aborts with the full JSON body embedded in the message.

Source

Thrown at g4f/Provider/OperaAria.py:253

                "Origin": "https://composer.opera-api.com",
                "User-Agent": cls._user_agent_v2,
            },
            data=media_bytes,
        ) as response:
            response.raise_for_status()

        # Step 3: Poll for completion
        for attempt in range(60):
            async with session.get(
                f"{cls.files_endpoint}{file_id}", headers=headers
            ) as response:
                response.raise_for_status()
                result = await response.json()
                status = result.get("upload_status")
                if status == "finished":
                    return file_id
                if status in ("failed", "error"):
                    raise Exception(f"Upload failed: {result}")
            await asyncio.sleep(min(1 + attempt * 0.3, 2))

        raise Exception(f"Upload timeout for {file_id}")

    @classmethod
    async def _process_media(
        cls,
        session: ClientSession,
        access_token: str,
        media: MediaListType,
        messages: Messages,
    ) -> list:
        """Process and upload all media (V2 only)."""
        attachments = []
        for media_data, media_name in merge_media(media, messages):
            try:
                if isinstance(media_data, str) and media_data.startswith("data:"):
                    media_bytes = base64.b64decode(media_data.split(",", 1)[1])

View on GitHub (pinned to 973504e177)

Solutions

  1. Read the `result` JSON in the message to identify the server-side failure reason.
  2. Convert media to a widely supported format (jpeg/png/mp4) and re-upload.
  3. Re-run to refresh the access token (tokens are obtained per call); if it persists, update g4f for API changes.
  4. Avoid passing the same media in both the media list and message content.

Example fix

// before
media = [('doc.pdf', open('doc.pdf','rb').read())]

// after - use a supported image format
media = [('photo.png', open('photo.png','rb').read())]
Defensive patterns

Strategy: try-catch

Validate before calling

from pathlib import Path
SUPPORTED = {'.png', '.jpg', '.jpeg', '.gif', '.mp4', '.webp'}

def opera_media_supported(name: str) -> bool:
    return Path(name).suffix.lower() in SUPPORTED

Try / catch

try:
    result = await OperaAria.create_async_generator(model, messages, media=media)
except Exception as e:
    if 'Upload failed' in str(e):
        result = await OperaAria.create_async_generator(model, messages)  # retry without media

Prevention

When it happens

Trigger: Uploading media via OperaAria when Opera's backend rejects or fails processing the file server-side: unsupported format, corrupted bytes, expired access token causing a degraded status, or size limits enforced after initial accept.

Common situations: Sending HEIC/txt/other formats Opera cannot process; auth token expired mid-poll (partial failures); flaky upstream storage; media passed both in `media` and embedded in messages causing double-upload conflicts.

Related errors


AI-assisted analysis of xtekky/gpt4free@973504e177 (2026-08-14). Data as JSON: /api/errors/f1a166ccd100971a. Report an issue: GitHub.