affaan-m/ECC · error · FalError
fal upload failed; provider details omitted
Error message
fal upload failed; provider details omitted
What it means
falapi.upload() calls fal_client.upload_file() to push the local file to fal.ai storage. If the upload raises for any reason, it raises FalError('fal upload failed; provider details omitted') with the original exception deliberately unchained (`from None`) because provider error strings may embed keys, signed URLs, or payload contents. This is a sanitized wrapper: the real cause is hidden on purpose, so diagnostics must come from context, not the exception.
Solutions
- Re-check FAL_KEY validity (dashboard -> keys) since auth failures are the most common hidden cause, then retry the upload.
- Retry with a smaller/stabler network path: check file size against provider limits, disable interfering proxies/VPN, and retry on a stable connection.
- Work around the upload when possible — pass publicly reachable URLs as inputs instead of local files, or retry with backoff if it is transient.
- If it persists, reproduce outside the pipeline with a minimal `fal_client.upload_file(...)` script to see the raw provider error (locally only, never in logs/CI), then fix the root cause.
Example fix
# before
except FalError:
pass # provider details omitted, no idea why
# after
try:
size = Path(asset).stat().st_size
except OSError:
raise
if size > MAX_UPLOAD_BYTES:
raise ValueError(f"{asset} exceeds fal.ai upload limit ({size} bytes)")
for attempt in range(3): # bounded retry with backoff
try:
url = upload(asset)
break
except FalError:
time.sleep(2 ** attempt)
else:
raise RuntimeError(f"upload of {asset} failed after 3 attempts") Defensive patterns
Strategy: retry
Validate before calling
from pathlib import Path
p = Path(path)
assert p.is_file(), f"missing file: {p}"
size = p.stat().st_size
assert size <= MAX_UPLOAD_BYTES, f"{p.name} too large for fal upload: {size} bytes" Try / catch
try:
url = upload(path)
except FalError:
# provider details are intentionally omitted; check key + network, then retry
verify_fal_key_valid()
url = upload(path) if attempts_left() else raise_upload_failure(path) Prevention
- Rotate/verify FAL_KEY regularly; a revoked key surfaces here as an opaque failure
- Keep uploaded assets within provider size limits; compress or split large files first
- Use bounded retries with exponential backoff for large uploads on flaky networks
- Never log provider exception strings from fal_client calls — they can contain keys and signed URLs
- Prefer passing public URLs as inputs when assets are already hosted, skipping the upload entirely
When it happens
Trigger: upload() (via upload_many()) in live mode, after api_key() succeeds, when _fal().upload_file(str(p)) raises — network interruption during upload, provider 401/403 on the storage endpoint, file size above provider limits, timeout on slow connections, or transient fal.ai storage errors.
Common situations: Expired or revoked FAL_KEY (401 mid-session); large multi-megabyte model/asset files failing on flaky networks or corporate proxies; payload exceeding fal.ai's upload size limits; firewall/VPN blocking the storage host; rate limiting after many consecutive uploads.
Related errors
- fal upload failed; provider details omitted
- fal call failed after one attempt; job acceptance may be…
- fal call failed after one attempt; job acceptance may be…
- fal upload failed; provider details omitted
- download failed; existing destination preserved
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/7f5263eddf06db7d.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/taste/falapi.py:317
if not p.exists():
raise FalError(f"cannot upload, file does not exist: {p}")
key = _cache_key(p)
with _UPLOAD_LOCK:
hit = _UPLOAD_CACHE.get(key)
if hit and (is_dry_run() == hit.startswith(DRY_RUN_HOST + "/")):
log.debug("upload cache hit: %s", p.name)
return hit
if is_dry_run():
url = f"{DRY_RUN_HOST}/uploads/{_digest(str(key))}/{p.name}"
log.info("[dry-run] would upload %s (%d bytes) -> %s", p, key[2], url)
else:
api_key()
try:
url = _fal().upload_file(str(p))
except Exception:
raise FalError("fal upload failed; provider details omitted") from None
log.info("uploaded %s -> %s", p.name, safe_url(url))
with _UPLOAD_LOCK:
_UPLOAD_CACHE[key] = url
return url
def upload_many(paths: Iterable[str | Path]) -> list[str]:
return [upload(p) for p in paths]
def clear_upload_cache() -> None:
with _UPLOAD_LOCK:
_UPLOAD_CACHE.clear()
# ---------------------------------------------------------------------------
# response parsingView on GitHub (pinned to 8321021c54)