From 96bf276ab9ef475b3eb4384a803258d80804a3ed Mon Sep 17 00:00:00 2001 From: jesus Date: Wed, 9 Sep 2026 22:36:09 +0000 Subject: [PATCH] fix(cli): remove the temp catalog when the atomic replace fails Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/proxy/client/cli/commands/agents.py | 6 +++++- tests/test_litellm/proxy/client/cli/test_agents.py | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) 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")