← back to Exo
Handle config.json not found (image models) (#1408)
2fbdb27bb13a7915d75bc3599f638817d4042ce8 · 2026-02-07 03:34:58 +0000 · ciaranbor
## Motivation
When downloading image models, a missing config.json file triggers a
FileNotFoundError inside download_file_with_retry. This error was being
caught by the generic except Exception handler and retried 3 times
before failing. Then, the whole thing would be retried from the start
## Changes
- src/exo/download/download_utils.py: Added FileNotFoundError to the
list of immediately-raised exceptions in download_file_with_retry,
alongside HuggingFaceAuthenticationError. This prevents useless retries
when a file genuinely doesn't exist on the remote.
- src/exo/master/api.py: Wrapped ModelCard.load(model_id) in a
try/except that converts failures into an HTTPException(400) with a
descriptive error message, giving API consumers a clear error response.
## Why It Works
- FileNotFoundError is a deterministic error — the file won't appear on
retry, so re-raising immediately avoids 3 wasted download attempts with
exponential backoff.
- Catching ModelCard.load() failures and returning a 400 HTTP response
prevents unhandled exceptions from surfacing as opaque 500 errors in the
API.
## Test Plan
### Manual Testing
Verified an image model not in model cards does not cause an infinite
error loop
Files touched
M src/exo/download/download_utils.pyM src/exo/master/api.py
Diff
commit 2fbdb27bb13a7915d75bc3599f638817d4042ce8
Author: ciaranbor <81697641+ciaranbor@users.noreply.github.com>
Date: Sat Feb 7 03:34:58 2026 +0000
Handle config.json not found (image models) (#1408)
## Motivation
When downloading image models, a missing config.json file triggers a
FileNotFoundError inside download_file_with_retry. This error was being
caught by the generic except Exception handler and retried 3 times
before failing. Then, the whole thing would be retried from the start
## Changes
- src/exo/download/download_utils.py: Added FileNotFoundError to the
list of immediately-raised exceptions in download_file_with_retry,
alongside HuggingFaceAuthenticationError. This prevents useless retries
when a file genuinely doesn't exist on the remote.
- src/exo/master/api.py: Wrapped ModelCard.load(model_id) in a
try/except that converts failures into an HTTPException(400) with a
descriptive error message, giving API consumers a clear error response.
## Why It Works
- FileNotFoundError is a deterministic error — the file won't appear on
retry, so re-raising immediately avoids 3 wasted download attempts with
exponential backoff.
- Catching ModelCard.load() failures and returning a 400 HTTP response
prevents unhandled exceptions from surfacing as opaque 500 errors in the
API.
## Test Plan
### Manual Testing
Verified an image model not in model cards does not cause an infinite
error loop
---
src/exo/download/download_utils.py | 2 ++
src/exo/master/api.py | 7 ++++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/exo/download/download_utils.py b/src/exo/download/download_utils.py
index e0554cd4..7974d504 100644
--- a/src/exo/download/download_utils.py
+++ b/src/exo/download/download_utils.py
@@ -457,6 +457,8 @@ async def download_file_with_retry(
)
except HuggingFaceAuthenticationError:
raise
+ except FileNotFoundError:
+ raise
except HuggingFaceRateLimitError as e:
if attempt == n_attempts - 1:
raise e
diff --git a/src/exo/master/api.py b/src/exo/master/api.py
index 935c41ea..ce98c354 100644
--- a/src/exo/master/api.py
+++ b/src/exo/master/api.py
@@ -386,7 +386,12 @@ class API:
if len(list(self.state.topology.list_nodes())) == 0:
return PlacementPreviewResponse(previews=[])
- model_card = await ModelCard.load(model_id)
+ try:
+ model_card = await ModelCard.load(model_id)
+ except Exception as exc:
+ raise HTTPException(
+ status_code=400, detail=f"Failed to load model card: {exc}"
+ ) from exc
instance_combinations: list[tuple[Sharding, InstanceMeta, int]] = []
for sharding in (Sharding.Pipeline, Sharding.Tensor):
for instance_meta in (InstanceMeta.MlxRing, InstanceMeta.MlxJaccl):
← 3f57416d Add image lightbox (#1414)
·
back to Exo
·
Address GPU timeouts (#1429) 4abdaaf7 →