affaan-m/ECC · error · FalError
download failed; existing destination preserved
Error message
download failed; existing destination preserved
What it means
download() writes to a temporary file in the destination directory and only atomically renames it onto dest after a fully successful transfer. Any non-FalError exception during the request or write (network error, DNS failure, permission error, decode error) is converted into this generic FalError; because the rename never happened, the pre-existing destination file is preserved untouched.
Solutions
- Check network connectivity and retry the download
- Verify dest.parent exists and is writable by the current user (mkdir -p, chmod)
- Increase the hardcoded timeout=300 in download() for large assets
- Run the underlying urllib opener manually to see the original exception (this handler discards it via 'from None')
Example fix
# before
path = download(url, dest) # opaque 'download failed' on any error
# after
try:
path = download(url, dest)
except FalError:
dest.parent.mkdir(parents=True, exist_ok=True)
import urllib.request
urllib.request.urlretrieve(url, '/tmp/dbg-asset') # surface real error
raise Defensive patterns
Strategy: try-catch
Validate before calling
assert dest.parent.exists() and os.access(dest.parent, os.W_OK), 'destination dir must be writable'
Try / catch
try:
download(url, dest)
except FalError as e:
if 'download failed' in str(e):
# real cause hidden; retry with a plain client to surface it
urllib.request.urlretrieve(url, dest.with_suffix('.tmp'))
raise Prevention
- Ensure the destination directory exists and is writable before calling
- Raise the hardcoded 300s timeout for large assets by patching download()
- Keep network retries around all download calls
- Remember the old destination file is preserved — check its mtime to know whether the new download succeeded
When it happens
Trigger: DNS resolution failure, connection reset/timeouts during opener.open or resp.read, SSL errors, permission denied writing into dest.parent, disk-full while writing the temp file, or urllib raising any unexpected exception.
Common situations: Offline/flaky network during a pipeline run; destination directory is read-only or owned by another user; long download exceeding the hardcoded timeout=300; antivirus or OS locking temp files in dest.parent.
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
- download failed; existing destination preserved
- download failed; existing destination preserved
- download length does not match declared size
- download length does not match declared size
- cannot open
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/d86265261f33f937.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/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)