From 1192f29450f1dc440d44b094817977f00475643c Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Wed, 8 Jul 2026 17:27:52 +0530 Subject: [PATCH] fix: Z.AI endpoint persist failure must not break URL resolution Review findings (hermes-pr-review Phase 2, 3-angle): - _save_auth_store() does real filesystem I/O (mkdir, O_EXCL create, fsync, atomic replace) and can raise on disk-full/permissions/lock-timeout. The persist ran bare in the success path, so a persist failure aborted _resolve_zai_base_url() after detection had already succeeded. Wrap the persist in try/except: log a warning and still return the detected URL (worst case: next start re-probes). - Readability: stage the payload in a local detected_endpoint instead of writing through the stale pre-lock 'state' dict, which is no longer what gets persisted. --- hermes_cli/auth.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/hermes_cli/auth.py b/hermes_cli/auth.py index 103c151e675..5cf6d50186a 100644 --- a/hermes_cli/auth.py +++ b/hermes_cli/auth.py @@ -701,23 +701,29 @@ def _resolve_zai_base_url(api_key: str, default_url: str, env_override: str) -> if detected and detected.get("base_url"): # Persist the detection result keyed on the API key hash. key_hash = hashlib.sha256(api_key.encode()).hexdigest()[:16] - state["detected_endpoint"] = { + detected_endpoint = { "base_url": detected["base_url"], "endpoint_id": detected.get("id", ""), "model": detected.get("model", ""), "label": detected.get("label", ""), "key_hash": key_hash, } - with _auth_store_lock(): - # Reload auth_store under lock to avoid overwriting concurrent changes - auth_store = _load_auth_store() - state_under_lock = _load_provider_state(auth_store, "zai") or {} - state_under_lock["detected_endpoint"] = state["detected_endpoint"] - # set_active=False: this runs from credential-pool env seeding - # (agent/credential_pool.py) for ANY user with a Z.AI key in env, - # and caching a probe result must not flip their active provider. - _store_provider_state(auth_store, "zai", state_under_lock, set_active=False) - _save_auth_store(auth_store) + # Persist failure (disk full, permissions, lock timeout) must not + # break resolution — detection already succeeded; worst case the + # next start re-probes. + try: + with _auth_store_lock(): + # Reload auth_store under lock to avoid overwriting concurrent changes + auth_store = _load_auth_store() + state_under_lock = _load_provider_state(auth_store, "zai") or {} + state_under_lock["detected_endpoint"] = detected_endpoint + # set_active=False: this runs from credential-pool env seeding + # (agent/credential_pool.py) for ANY user with a Z.AI key in env, + # and caching a probe result must not flip their active provider. + _store_provider_state(auth_store, "zai", state_under_lock, set_active=False) + _save_auth_store(auth_store) + except Exception as exc: + logger.warning("Z.AI: could not persist detected endpoint (%s); will re-probe next start", exc) logger.info("Z.AI: auto-detected endpoint %s (%s)", detected["label"], detected["base_url"]) return detected["base_url"]