{"record":{"id":"dabc448ff5444619","repo":"affaan-m/ECC","slug":"download-length-does-not-match-declared-size","errorCode":null,"errorMessage":"download length does not match declared size","messagePattern":"download length does not match declared size","errorType":"exception","errorClass":"FalError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/falapi.py","lineNumber":715,"sourceCode":"        with opener.open(req, timeout=300) as resp:\n            declared = getattr(resp, \"headers\", {}).get(\"Content-Length\")\n            expected = int(declared) if declared is not None else None\n            if expected is not None and not 0 <= expected <= MAX_DOWNLOAD_BYTES:\n                raise FalError(\"download declares an invalid or excessive size\")\n            with tempfile.NamedTemporaryFile(dir=dest.parent, prefix=\".taste-download-\",\n                                             delete=False) as fh:\n                temporary = Path(fh.name)\n                total = 0\n                while True:\n                    chunk = resp.read(min(1024 * 1024, MAX_DOWNLOAD_BYTES - total + 1))\n                    if not chunk:\n                        break\n                    total += len(chunk)\n                    if total > MAX_DOWNLOAD_BYTES:\n                        raise FalError(\"download exceeds maximum allowed size\")\n                    fh.write(chunk)\n                if expected is not None and total != expected:\n                    raise FalError(\"download length does not match declared size\")\n        os.replace(temporary, dest)\n        temporary = None\n    except FalError:\n        raise\n    except Exception:\n        raise FalError(\"download failed; existing destination preserved\") from None\n    finally:\n        if temporary is not None:\n            temporary.unlink(missing_ok=True)\n    return dest\n\n\n# ---------------------------------------------------------------------------\n# dry-run stubs\n# ---------------------------------------------------------------------------\n\n\ndef _digest(*parts: Any) -> str:","sourceCodeStart":697,"sourceCodeEnd":733,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/falapi.py#L697-L733","documentation":"download() in falapi.py streams the remote file to a temp file while counting bytes. If the server declared a Content-Length and the streamed total differs from it, the file is incomplete or corrupted, so download() raises FalError instead of promoting a truncated/corrupt file to the destination. The temp file is removed and the existing destination is left untouched.","triggerScenarios":"Calling download(url, dest, expected=<size>) (or downloading from a URL whose Content-Length is known) when the connection drops mid-stream, the server sends fewer/more bytes than declared, or a proxy rewrites the body without updating Content-Length.","commonSituations":"Flaky networks or Wi-Fi drops during a large fal.ai media download; CDN edge truncation; content-encoding (gzip) double-counting bytes; server-side timeouts on slow links.","solutions":["Re-run the download; transient truncation is usually fixed on retry.","Check network stability / disable proxies or VPNs that can truncate or re-encode responses.","Verify the server's Content-Length matches the actual resource size (curl -I) and compare with the expected value passed in.","If the source systematically reports a wrong size, fetch the resource from a mirror or updated URL."],"exampleFix":"# before (fragile, no retry)\napi.download(url, dest, expected=size)\n\n# after (bounded retry for transient truncation)\nfor attempt in range(3):\n    try:\n        api.download(url, dest, expected=size)\n        break\n    except api.FalError:\n        if attempt == 2:\n            raise\n        time.sleep(2 ** attempt)","handlingStrategy":"retry","validationCode":"import os\nhead = urllib.request.urlopen(url)\nexpected = int(head.headers.get('Content-Length', 0))\nif expected > MAX_ALLOWED:\n    raise ValueError('file too large')\nos.remove(dest) if os.path.exists(dest) else None","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        api.download(url, dest, expected=size)\n        break\n    except api.FalError as e:\n        if attempt == 2 or 'exceeds' in str(e):\n            raise\n        time.sleep(2 ** attempt)","preventionTips":["Retry downloads with exponential backoff; truncation is usually transient.","Check Content-Length with a HEAD request before downloading large media.","Avoid unreliable proxies/VPNs for large transfers.","Keep the existing destination file — the API preserves it precisely so retries are safe."],"tags":["network","download","integrity","python"],"backgroundTag":"checksum-mismatch","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}