fix(models): keep raw exception text out of client-construction 503s

Review: the wrapped ValueError is echoed in 503 bodies, and arbitrary
SDK exception text can embed filesystem paths. Echo the exception type
only; log the full exception with traceback at the raise site.
This commit is contained in:
Patrick Buckley
2026-07-06 21:04:12 -07:00
parent 9c2e809b26
commit a029849724
2 changed files with 18 additions and 3 deletions
+6 -1
View File
@@ -176,12 +176,17 @@ class TestModelRegistry:
with (
patch(
"turnstone.core.model_registry.create_client",
side_effect=FileNotFoundError(2, "No such file or directory"),
side_effect=FileNotFoundError(2, "No such file", "/gone/cacert.pem"),
),
pytest.raises(ValueError, match="'default'.*FileNotFoundError") as excinfo,
):
reg.get_client("default")
assert isinstance(excinfo.value.__cause__, FileNotFoundError)
# The message is echoed in 503 bodies: exception TYPE only — the
# raw exception text can embed filesystem paths and must stay in
# the server log.
assert "/gone/cacert.pem" not in str(excinfo.value)
assert "No such file" not in str(excinfo.value)
# Nothing half-constructed may be cached — a later call with a
# repaired environment must construct for real.
assert "default" not in reg._clients
+12 -2
View File
@@ -159,10 +159,20 @@ class ModelRegistry:
# path that a venv rebuild deleted (FileNotFoundError).
# Routes map ValueError to a 503 with the message;
# anything else surfaces as an opaque 500, so re-type
# here where the alias is known.
# here where the alias is known. The ValueError text is
# echoed to HTTP callers, so it carries only the
# exception TYPE — arbitrary SDK exception text can
# embed filesystem paths; the full detail goes to the
# server log instead.
log.warning(
"Client construction failed for model alias %r (provider %s)",
alias,
cfg.provider,
exc_info=True,
)
raise ValueError(
f"failed to construct {cfg.provider} client for model "
f"alias {alias!r}: {type(exc).__name__}: {exc}"
f"alias {alias!r}: {type(exc).__name__} (details in server log)"
) from exc
return self._clients[alias]