calesthio/OpenMontage · error · AtlasError

Atlas Cloud upload returned no URL: {str(data)[:500]}

Error message

Atlas Cloud upload returned no URL: {str(data)[:500]}

What it means

Raised by upload_media when the upload request and envelope parsing succeeded but the payload contains neither download_url nor url — the two documented shapes for the hosted-asset response. The server accepted the file but the response lacks any retrievable location, so the caller cannot proceed to use it as a reference URL. The truncated payload is included.

Source

Thrown at tools/atlas_client.py:216

        raise AtlasError(f"Cannot upload — file not found: {path}")

    try:
        with path.open("rb") as handle:
            response = requests.post(
                UPLOAD_MEDIA_ENDPOINT,
                headers=_headers(api_key, json_body=False),
                files={"file": (path.name, handle)},
                timeout=timeout,
            )
    except Exception as exc:  # noqa: BLE001
        raise AtlasError(f"Uploading {path.name} to Atlas Cloud failed: {exc}") from exc

    _raise_for_status(response, "Atlas Cloud upload")
    data = _payload_of(response)

    url = data.get("download_url") or data.get("url")
    if not url:
        raise AtlasError(f"Atlas Cloud upload returned no URL: {str(data)[:500]}")
    return str(url)


def download(url: str, output_path: str | Path, timeout: int = 300) -> Path:
    """Download a generated asset to disk and return the written path."""
    import requests

    try:
        response = requests.get(url, timeout=timeout)
    except Exception as exc:  # noqa: BLE001
        raise AtlasError(f"Downloading Atlas Cloud output failed: {exc}") from exc

    _raise_for_status(response, "Atlas Cloud output download")

    path = Path(output_path)
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_bytes(response.content)
    return path

View on GitHub (pinned to 95e1c3d0ab)

Solutions

  1. Log the included payload snippet to see which field (if any) carries the URL, then extend the data.get('download_url') or data.get('url') chain in the client
  2. Retry the upload once — empty data on success envelopes is often transient
  3. Confirm you are hitting the documented UPLOAD_MEDIA_ENDPOINT for your Atlas API version
  4. Report to Atlas support if code 200 with no URL persists on their current endpoint

Example fix

// before
url = data.get("download_url") or data.get("url")

// after — tolerate a third documented shape
url = (
    data.get("download_url")
    or data.get("url")
    or data.get("file", {}).get("url")
)
Defensive patterns

Strategy: validation

Type guard

def upload_payload_has_url(data: dict) -> bool:
    return bool(data.get("download_url") or data.get("url"))

Try / catch

try:
    url = atlas_client.upload_media(path, api_key)
except AtlasError as e:
    if "returned no URL" in str(e):
        time.sleep(3)
        url = atlas_client.upload_media(path, api_key)  # empty-data envelopes are often transient
    else:
        raise

Prevention

When it happens

Trigger: Atlas API drift adding a new field name for the hosted URL; the endpoint returning an acknowledgment-only envelope ({code:200, data:{}}) because the upload silently failed server-side; routing the upload to a different endpoint version that uses another schema.

Common situations: Client library out of date relative to the live Atlas API; regional endpoint variants with different response fields; server-side storage failures that still return success envelopes.

Related errors


AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15). Data as JSON: /api/errors/402d759befbe5ca0. Report an issue: GitHub.