diff --git a/litellm/proxy/client/cli/commands/agents.py b/litellm/proxy/client/cli/commands/agents.py index 8e3698985af..0354aefa95c 100644 --- a/litellm/proxy/client/cli/commands/agents.py +++ b/litellm/proxy/client/cli/commands/agents.py @@ -453,7 +453,11 @@ def _replace_file(path: Path, text: str) -> None: path.parent.mkdir(parents=True, exist_ok=True) with tempfile.NamedTemporaryFile("w", encoding="utf-8", dir=path.parent, delete=False) as tmp: _ = tmp.write(text) - os.replace(tmp.name, path) + try: + os.replace(tmp.name, path) + except OSError: + Path(tmp.name).unlink(missing_ok=True) + raise def codex_model_sync_args( diff --git a/tests/test_litellm/proxy/client/cli/test_agents.py b/tests/test_litellm/proxy/client/cli/test_agents.py index 75e42c3eaa0..3020b770e62 100644 --- a/tests/test_litellm/proxy/client/cli/test_agents.py +++ b/tests/test_litellm/proxy/client/cli/test_agents.py @@ -481,6 +481,13 @@ class TestCodexModelSync: assert isinstance(result, ModelSyncSkipped) assert "could not write" in result.reason + def test_failed_replace_is_reported_and_leaves_no_temp_file(self, tmp_path): + (tmp_path / "litellm-models.json").mkdir() + _, result = self._sync(self._listing(self._row("m")), tmp_path) + assert isinstance(result, ModelSyncSkipped) + assert "could not write" in result.reason + assert [p.name for p in tmp_path.iterdir()] == ["litellm-models.json"] + def test_unreachable_proxy_is_reported_not_raised(self, tmp_path): def boom(*a, **k): raise requests.ConnectionError("refused")