From 6ececcb8881f1ede7f13aba0a22e97884634c6a1 Mon Sep 17 00:00:00 2001 From: "posthog[bot]" <206114724+posthog[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 19:38:14 +0000 Subject: [PATCH 1/2] fix(ai/prompts): give HTTP 401 a real error message Prompt fetches that fail with 401 fell through to a generic "HTTP 401" error that gave no hint the personal API key was missing, expired, or the wrong type. Add a 401 branch, alongside the existing 403 branch, that names the likely causes, including the common personal-key-versus-secret-key mixup. Generated-By: PostHog Desktop Task-Id: cece44a6-1807-431b-8a3e-7f00e0d75eac --- posthog/ai/prompts.py | 9 +++++++++ posthog/test/ai/test_prompts.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/posthog/ai/prompts.py b/posthog/ai/prompts.py index 0e5ef38bf..e06cc1c10 100644 --- a/posthog/ai/prompts.py +++ b/posthog/ai/prompts.py @@ -532,6 +532,15 @@ def _fetch_prompt_from_api( if response.status_code == 404: raise Exception(f"[PostHog Prompts] {prompt_title} not found") + if response.status_code == 401: + raise Exception( + f"[PostHog Prompts] Authentication failed for {prompt_reference}. " + "The personal_api_key may be missing, expired, or the wrong type. " + "Prompt fetches need a personal API key (starts with 'phx_'), not a " + "project secret key. Check that you passed a personal_api_key and not " + "a secret key." + ) + if response.status_code == 403: raise Exception( f"[PostHog Prompts] Access denied for {prompt_reference}. " diff --git a/posthog/test/ai/test_prompts.py b/posthog/test/ai/test_prompts.py index 15d4b9117..774646d18 100644 --- a/posthog/test/ai/test_prompts.py +++ b/posthog/test/ai/test_prompts.py @@ -402,6 +402,22 @@ def test_handle_403_response(self, mock_get_session): 'Access denied for prompt "restricted-prompt"', str(context.exception) ) + @patch("posthog.ai.prompts._get_session") + def test_handle_401_response(self, mock_get_session): + """Should explain the likely auth causes on a 401 response.""" + mock_get = mock_get_session.return_value.get + mock_get.return_value = MockResponse(status_code=401, ok=False) + + posthog = self.create_mock_posthog() + prompts = Prompts(posthog) + + with self.assertRaises(Exception) as context: + prompts.get("restricted-prompt", with_metadata=False) + + message = str(context.exception) + self.assertIn('Authentication failed for prompt "restricted-prompt"', message) + self.assertIn("personal API key", message) + def test_throw_when_no_personal_api_key_configured(self): """Should throw when no personal_api_key is configured.""" posthog = self.create_mock_posthog(personal_api_key=None) From bcff710fcba7475f943e9da3c867ad62bfccdb3f Mon Sep 17 00:00:00 2001 From: "posthog[bot]" <206114724+posthog[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 19:45:12 +0000 Subject: [PATCH 2/2] fix(ai/prompts): separate key type from param name in 401 message The 401 auth-failure message told users to "pass a personal_api_key and not a secret key", conflating the key type (personal API key vs project secret key) with the parameter name. A correctly-configured client user (`Posthog(..., secret_key='phx_...')`) would read this as "switch to personal_api_key=", which resolves to the same value and re-triggers the 401 plus a DeprecationWarning. Reword so the message names the key type (personal API key, starts with 'phx_'; a project secret key is not accepted) separately from the parameter to use per entry point: personal_api_key when constructing Prompts directly, secret_key when configuring the PostHog client. Generated-By: PostHog Desktop Task-Id: add0fc6a-5a9d-4035-882a-aa60824939bf --- posthog/ai/prompts.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/posthog/ai/prompts.py b/posthog/ai/prompts.py index e06cc1c10..a3d4eba28 100644 --- a/posthog/ai/prompts.py +++ b/posthog/ai/prompts.py @@ -535,10 +535,11 @@ def _fetch_prompt_from_api( if response.status_code == 401: raise Exception( f"[PostHog Prompts] Authentication failed for {prompt_reference}. " - "The personal_api_key may be missing, expired, or the wrong type. " - "Prompt fetches need a personal API key (starts with 'phx_'), not a " - "project secret key. Check that you passed a personal_api_key and not " - "a secret key." + "The key may be missing, expired, or the wrong type. Prompt fetches " + "require a personal API key (starts with 'phx_'); a project secret " + "key is not accepted. Pass this key as personal_api_key when you " + "construct Prompts directly, or as secret_key when you configure the " + "PostHog client." ) if response.status_code == 403: