From cedefc53264f521f5a55be61b746a39c6ada8d4e Mon Sep 17 00:00:00 2001 From: David Brailovsky Date: Wed, 21 Oct 2026 10:11:54 +0200 Subject: [PATCH] fix(ai): handle ChatGPT Business workspace usage limit errors Sign in with ChatGPT on a ChatGPT Business plan can fail with subscription_sharing_workplace_individual_usage_limit_exceeded. Only the workspace admin can raise this limit, so retrying never helps. - Mark the error as non-retryable - Add a hint to the error message telling the user to ask their workspace admin to increase the limit --- packages/ai/CHANGELOG.md | 1 + packages/ai/src/api/openai-responses.ts | 13 ++++++++++--- packages/ai/src/utils/retry.ts | 3 +++ packages/ai/test/retry.test.ts | 6 ++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 56d61384b..79b819682 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -12,6 +12,7 @@ - Added `AI_TELEMETRY_SCHEMA` and opt-in `pi.ai.request`/`pi.ai.poll` tracing around Models requests, with content-free first-event, block-size, and final usage attributes, plus duration, token, and USD cost metrics through `telemetry.metrics`. - Failed model request spans report `provider_error` status with up to 500 error-message characters; cancelled requests keep `ok` status with `stop: "aborted"`. - Added `MiniMax-M3.1-Flash` to the `minimax` and `minimax-cn` providers, with thinking levels low through max sent as `output_config.effort`. Thinking cannot be turned off for this model. New MiniMax models from models.dev now appear without a manual allowlist entry; only the older M2, M2.1, M2.5, and M2.5-highspeed models stay hidden ([#11121](https://github.com/earendil-works/pi/issues/11121)) +- Sign in with ChatGPT: ChatGPT Business workspace usage-limit errors are not retried and tell the user to ask their workspace admin to increase the limit. ### Changed diff --git a/packages/ai/src/api/openai-responses.ts b/packages/ai/src/api/openai-responses.ts index 697abbeb8..da04f0a0f 100644 --- a/packages/ai/src/api/openai-responses.ts +++ b/packages/ai/src/api/openai-responses.ts @@ -37,6 +37,8 @@ const OPENAI_TOOL_CALL_PROVIDERS = new Set(["openai", "openai-codex", "opencode" // OpenAI Responses rejects max_output_tokens below 16: https://github.com/earendil-works/pi/issues/6265 const OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16; const CHATGPT_USAGE_URL = "https://chatgpt.com/settings/usage"; +const CHATGPT_WORKSPACE_LIMIT_HINT = + "You've reached your ChatGPT workspace's usage limit. Ask your workspace admin to increase it at admin.openai.com → Workspace → Usage limits."; // Fixed reasoning.effort while configuration_update items carry the thinking level. const CONFIGURATION_UPDATE_REQUEST_EFFORT = "medium"; @@ -258,9 +260,14 @@ export const stream: StreamFunction<"openai-responses", OpenAIResponsesOptions> `${model.provider === "openai" ? "OpenAI" : model.provider} API error`, ); // Sign in with ChatGPT shares the subscription's usage limit with other apps. - output.errorMessage = errorMessage.includes("subscription_sharing_usage_limit_exceeded") - ? `${errorMessage}\nCheck your ChatGPT usage: ${CHATGPT_USAGE_URL}` - : errorMessage; + // On ChatGPT Business plans, the workspace admin also sets a per-user limit. + if (errorMessage.includes("subscription_sharing_usage_limit_exceeded")) { + output.errorMessage = `${errorMessage}\nCheck your ChatGPT usage: ${CHATGPT_USAGE_URL}`; + } else if (errorMessage.includes("subscription_sharing_workplace_individual_usage_limit_exceeded")) { + output.errorMessage = `${errorMessage}\n${CHATGPT_WORKSPACE_LIMIT_HINT}`; + } else { + output.errorMessage = errorMessage; + } stream.push({ type: "error", reason: output.stopReason, error: output }); stream.end(); } diff --git a/packages/ai/src/utils/retry.ts b/packages/ai/src/utils/retry.ts index b29ff146a..ca5eb7d68 100644 --- a/packages/ai/src/utils/retry.ts +++ b/packages/ai/src/utils/retry.ts @@ -25,6 +25,9 @@ const NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([ // Sign in with ChatGPT: the subscription's shared usage limit, which resets // after hours rather than seconds. "subscription_sharing_usage_limit_exceeded", + // Sign in with ChatGPT on a ChatGPT Business plan: a usage limit set by the + // workspace admin. Only the admin can raise it. + "subscription_sharing_workplace_individual_usage_limit_exceeded", ]); const RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([ diff --git a/packages/ai/test/retry.test.ts b/packages/ai/test/retry.test.ts index ffc46fcd8..e96efc0f2 100644 --- a/packages/ai/test/retry.test.ts +++ b/packages/ai/test/retry.test.ts @@ -126,6 +126,12 @@ describe("provider retry classification", () => { expect(isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage }))).toBe(false); }); + it("keeps the ChatGPT Business workspace usage limit non-retryable", () => { + const errorMessage = + 'OpenAI API error (429): {"code":"subscription_sharing_workplace_individual_usage_limit_exceeded","message":"Usage limit reached."}'; + expect(isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage }))).toBe(false); + }); + it.each([ "subscription_sharing_usage_unavailable: Usage cannot be checked.", "subscription_sharing_user_unavailable: User cannot be loaded.",