affaan-m/ECC · error · FalError

download failed; existing destination preserved

Error message

download failed; existing destination preserved

What it means

download() wraps the whole transfer in a generic except that converts any non-FalError exception (socket errors, TLS failures, HTTPError, OSError) into a single FalError with a user-safe message. The original cause is intentionally discarded (from None) and the pre-existing destination file is left untouched because the temp file was never os.replace()'d.

Solutions

  1. Check network connectivity and that fal.media is reachable (curl -I the URL)
  2. Inspect whether the destination directory exists and is writable, since temp files are created there
  3. Catch FalError and retry with backoff for transient server/network issues
  4. Temporarily instrument or re-raise to see the underlying cause, since the message hides it

Example fix

// before
FalError: download failed; existing destination preserved
// after
try:
    download(url, dest)
except FalError:
    if not dest.exists():
        raise RuntimeError(f"download failed and no fallback at {dest}")
Defensive patterns

Strategy: try-catch

Validate before calling

import socket
socket.create_connection(("fal.media", 443), timeout=5)  # pre-flight reachability

Try / catch

try:
    download(url, dest)
except FalError as e:
    if not dest.exists():
        raise RuntimeError(f"no prior asset at {dest}: {e}") from e
    log.info("using existing %s after failed refresh", dest)

Prevention

When it happens

Trigger: DNS resolution failure, connection refused/reset, TLS handshake error, HTTP 4xx/5xx from the server, timeout after 300s, or local filesystem error creating/writing the temp file.

Common situations: No internet or blocked egress in CI; fal.media temporarily down or rate-limiting; corporate proxy breaking HTTPS; destination directory not writable.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at skills/taste-distillation/scripts/taste/falapi.py:721

                                             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
# ---------------------------------------------------------------------------


def _digest(*parts: Any) -> str:
    h = hashlib.sha256("|".join(str(p) for p in parts).encode("utf-8"))
    return h.hexdigest()[:12]


def _stub_from_schema(schema: dict) -> dict:
    """Build a stub object with the same keys and types as ``schema``."""

View on GitHub (pinned to 8321021c54)