Skip to content

fix(client): raise auth exception synchronously in Client.init()#1370

Open
xodn348 wants to merge 1 commit into
AgentOps-AI:mainfrom
xodn348:fix/client-init-silent-auth-failure
Open

fix(client): raise auth exception synchronously in Client.init()#1370
xodn348 wants to merge 1 commit into
AgentOps-AI:mainfrom
xodn348:fix/client-init-silent-auth-failure

Conversation

@xodn348
Copy link
Copy Markdown

@xodn348 xodn348 commented May 11, 2026

Summary

Fixes #1336Client.init() silently succeeds with an invalid API key.

Root cause: _start_auth_task() fired authentication off in a background daemon thread without joining. Any exception raised by fetch_auth_token (e.g. InvalidApiKeyException) was swallowed inside the thread, so init() unconditionally set _initialized = True and returned a session object even when the key was wrong.

Changes:

  • agentops/client/api/versions/v3.pyfetch_auth_token now raises InvalidApiKeyException (instead of returning None) when the server returns no token or the HTTP request fails, so callers get a typed, informative error.
  • agentops/client/client.py_fetch_auth_async no longer wraps the whole body in a blanket except Exception: return None; exceptions propagate naturally. _start_auth_task in synchronous contexts (no running event loop) now joins the auth thread and re-raises any exception, surfacing failures immediately to init().
  • Tests — Updated fetch_auth_token mocks from MagicMock.return_value = dict to AsyncMock(return_value=dict) since the method is async. Also fixed the wrong patch target in test_session.py (agentops.client.api.ApiClientagentops.client.client.ApiClient). Added assert not client.initialized to the invalid-key test.

Before:

import agentops
agentops.init(api_key="not-a-real-key")  # succeeds silently, _initialized=True

After:

import agentops
agentops.init(api_key="not-a-real-key")
# raises: InvalidApiKeyException: API Key is invalid: {not-a-real-key}.
#         Find your API key at https://api.agentops.ai/settings/projects

Note on async callers: When init() is called from inside a running event loop, the auth task is still scheduled as a background asyncio.Task (blocking would deadlock the loop). This is an inherent limitation of mixing sync/async init; a future improvement could make init() itself async or expose an await client.verify_auth() helper.

Local test output

=== LOCAL_TEST_PASSED ===
tests/integration/test_auth_flow.py::test_auth_flow PASSED
tests/integration/test_auth_flow.py::test_auth_flow_invalid_key PASSED
tests/unit/test_session.py (21 tests) PASSED
24 passed in 0.84s
=== LOCAL_TEST_PASSED ===

Previously, _start_auth_task() fired authentication off in a daemon thread
without joining, so any InvalidApiKeyException from fetch_auth_token was
silently swallowed and Client.init() always set _initialized=True regardless
of whether the key was valid.

- v3.fetch_auth_token now raises InvalidApiKeyException instead of returning
  None when the server returns no token or the request fails outright.
- _fetch_auth_async propagates exceptions rather than catching them.
- _start_auth_task in synchronous contexts (no running event loop) joins the
  auth thread and re-raises, surfacing failures immediately to the caller.
- Update test mocks to use AsyncMock for the async fetch_auth_token method,
  and fix the wrong patch target in test_session.py (api → client module).

Closes AgentOps-AI#1336
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42e3415196

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread agentops/client/client.py
Comment on lines 129 to +130
self._auth_task = loop.create_task(self._fetch_auth_async(api_key))
else:
# Create new event loop in background thread
def run_async_auth():
asyncio.run(self._fetch_auth_async(api_key))
return
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Propagate auth failures when an event loop is running

When init() is called from an async context such as an ASGI startup hook or notebook, this branch only schedules _fetch_auth_async() and returns, so any InvalidApiKeyException raised by fetch_auth_token() stays on the background task while init() continues and later marks the client initialized. This means the new synchronous auth failure behavior still does not apply in running-loop environments, and invalid credentials can be silently accepted until export fails.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Client.init() silently succeeds with invalid API key — async auth swallows exceptions

1 participant