affaan-m/ECC · error · FalError

download exceeds maximum allowed size

Error message

download exceeds maximum allowed size

What it means

FalError raised during the streaming read loop of download() when the bytes actually received exceed MAX_DOWNLOAD_BYTES, even if no (or an understated) Content-Length was declared. This is the enforced hard cap on download size, preventing unbounded writes to disk from a malicious or misbehaving server.

Solutions

  1. Check the asset size before download (HEAD request) and avoid oversized files
  2. Download genuinely large assets with a different tool outside this library's cap
  3. If you control the generation parameters, reduce output resolution/duration so the artifact fits under the cap
  4. Deliberately raise MAX_DOWNLOAD_BYTES in the module if your workflow legitimately needs bigger files

Example fix

// before
download(video_url, "output.mp4")  # 4K, ~3GB
// after
import urllib.request
size = int(urllib.request.urlopen(urllib.request.Request(video_url, method="HEAD")).headers.get("Content-Length", 0))
assert size <= MAX_DOWNLOAD_BYTES, f"{size} bytes exceeds cap"
download(video_url, "output.mp4")
Defensive patterns

Strategy: try-catch

Validate before calling

import urllib.request
req = urllib.request.Request(url, method="HEAD")
with urllib.request.urlopen(req) as r:
    clen = r.headers.get("Content-Length")
if clen is not None and int(clen) > MAX_DOWNLOAD_BYTES:
    raise SystemExit("skip: streamed asset would exceed download cap")

Try / catch

try:
    download(url, dest)
except FalError as e:
    if "exceeds maximum" in str(e):
        logging.error("streamed download exceeded cap; partial file cleaned up for %s", safe_url(url))
    raise

Prevention

When it happens

Trigger: Downloading a file whose streamed body exceeds MAX_DOWNLOAD_BYTES while Content-Length is absent or lies (chunked transfer, compressed responses, misconfigured proxies).

Common situations: Chunked-encoding responses with no Content-Length that turn out to be huge; a redirect to a large asset; corrupted provider responses serving much more data than declared.

Understand the failure class

Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/2da9dfe1b03dca7b. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/falapi.py:712

    opener = urllib.request.build_opener(_SafeRedirect())
    temporary = None
    try:
        with opener.open(req, timeout=300) as resp:
            declared = getattr(resp, "headers", {}).get("Content-Length")
            expected = int(declared) if declared is not None else None
            if expected is not None and not 0 <= expected <= MAX_DOWNLOAD_BYTES:
                raise FalError("download declares an invalid or excessive size")
            with tempfile.NamedTemporaryFile(dir=dest.parent, prefix=".taste-download-",
                                             delete=False) as fh:
                temporary = Path(fh.name)
                total = 0
                while True:
                    chunk = resp.read(min(1024 * 1024, MAX_DOWNLOAD_BYTES - total + 1))
                    if not chunk:
                        break
                    total += len(chunk)
                    if total > MAX_DOWNLOAD_BYTES:
                        raise FalError("download exceeds maximum allowed size")
                    fh.write(chunk)
                if expected is not None and total != expected:
                    raise FalError("download length does not match declared size")
        os.replace(temporary, dest)
        temporary = None
    except FalError:
        raise
    except Exception:
        raise FalError("download failed; existing destination preserved") from None
    finally:
        if temporary is not None:
            temporary.unlink(missing_ok=True)
    return dest


# ---------------------------------------------------------------------------
# dry-run stubs
# ---------------------------------------------------------------------------

View on GitHub (pinned to 8321021c54)