{"record":{"id":"7f5263eddf06db7d","repo":"affaan-m/ECC","slug":"fal-upload-failed-provider-details-omitted-falapi","errorCode":null,"errorMessage":"fal upload failed; provider details omitted","messagePattern":"fal upload failed; provider details omitted","errorType":"exception","errorClass":"FalError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/taste/falapi.py","lineNumber":317,"sourceCode":"    if not p.exists():\n        raise FalError(f\"cannot upload, file does not exist: {p}\")\n\n    key = _cache_key(p)\n    with _UPLOAD_LOCK:\n        hit = _UPLOAD_CACHE.get(key)\n    if hit and (is_dry_run() == hit.startswith(DRY_RUN_HOST + \"/\")):\n        log.debug(\"upload cache hit: %s\", p.name)\n        return hit\n\n    if is_dry_run():\n        url = f\"{DRY_RUN_HOST}/uploads/{_digest(str(key))}/{p.name}\"\n        log.info(\"[dry-run] would upload %s (%d bytes) -> %s\", p, key[2], url)\n    else:\n        api_key()\n        try:\n            url = _fal().upload_file(str(p))\n        except Exception:\n            raise FalError(\"fal upload failed; provider details omitted\") from None\n        log.info(\"uploaded %s -> %s\", p.name, safe_url(url))\n\n    with _UPLOAD_LOCK:\n        _UPLOAD_CACHE[key] = url\n    return url\n\n\ndef upload_many(paths: Iterable[str | Path]) -> list[str]:\n    return [upload(p) for p in paths]\n\n\ndef clear_upload_cache() -> None:\n    with _UPLOAD_LOCK:\n        _UPLOAD_CACHE.clear()\n\n\n# ---------------------------------------------------------------------------\n# response parsing","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/taste/falapi.py#L299-L335","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nexcept FalError:\n    pass  # provider details omitted, no idea why\n\n# after\ntry:\n    size = Path(asset).stat().st_size\nexcept OSError:\n    raise\nif size > MAX_UPLOAD_BYTES:\n    raise ValueError(f\"{asset} exceeds fal.ai upload limit ({size} bytes)\")\nfor attempt in range(3):  # bounded retry with backoff\n    try:\n        url = upload(asset)\n        break\n    except FalError:\n        time.sleep(2 ** attempt)\nelse:\n    raise RuntimeError(f\"upload of {asset} failed after 3 attempts\")","handlingStrategy":"retry","validationCode":"from pathlib import Path\np = Path(path)\nassert p.is_file(), f\"missing file: {p}\"\nsize = p.stat().st_size\nassert size <= MAX_UPLOAD_BYTES, f\"{p.name} too large for fal upload: {size} bytes\"","typeGuard":null,"tryCatchPattern":"try:\n    url = upload(path)\nexcept FalError:\n    # provider details are intentionally omitted; check key + network, then retry\n    verify_fal_key_valid()\n    url = upload(path) if attempts_left() else raise_upload_failure(path)","preventionTips":["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"],"tags":["python","upload","network","api"],"backgroundTag":"upload-failed","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"}