feat(llm-gateway): add billing-denial error codes and legacy-client shim - #71343
Conversation
|
Hey @adboio! 👋 It looks like your git author email on this PR isn't your
You can fix it for this repo with: git config user.email "you@posthog.com"Or set it globally with |
The free-tier model-gate 403 now uses the standard error envelope with a
machine-readable code ("model_gate"), and its message carries a
"(rate_limit)" suffix so pre-cutover PostHog Code desktop builds route it
to their usage-limit modal instead of tearing the session down.
Throttle 429s repeat the reason in error.message (SDK error strings often
surface only the message) and carry the throttle scope as error.code so
clients can classify the limit cause without parsing prose.
Generated-By: PostHog Code
Task-Id: 1039ea23-9930-44e2-9888-b05cf8b129ec
64ceb77 to
6ac2179
Compare
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
Reviews (1): Last reviewed commit: "feat(llm-gateway): add billing-denial er..." | Re-trigger Greptile |
TestClient-level: an unbilled OAuth caller requesting a premium model gets
a top-level error envelope (never FastAPI's {"detail": ...} nesting) with
code "model_gate" and the "(rate_limit)" legacy-client shim in the message,
covering the raise site and the exception-handler unwrap together.
Generated-By: PostHog Code
Task-Id: 1039ea23-9930-44e2-9888-b05cf8b129ec
There was a problem hiding this comment.
Only the wire shape of existing 403/429 error responses changes (structured envelope + machine-readable codes for legacy-client compat); the underlying billing/gate decision logic is untouched, and the change has an independent current-head approval from a human teammate plus tests pinning the new body end-to-end.
- Author wrote 50% of the modified lines and has 10 merged PRs in these paths (familiarity MODERATE).
- charlesvien reviewed the current head.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 20L, 1F substantive, 87L/3F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1b-small (87L, 3F, single-area, feat) |
| stamphog 2.0.0b3 | .stamphog/policy.yml @ 238d8b5 · reviewed head c4ef911 |

Problem
PostHog Code's usage-based billing cutover (#70951) gates unbilled orgs to the free-tier model list, but the gate's 403 goes out as a bare FastAPI
detailstring. Pre-cutover desktop builds classify errors by substring: they treat that 403 as a fatal session error and tear a healthy session down ("Connection lost" + recovery loops), and no client can tell which limit tripped a 429 without parsing prose.Why: installed desktop builds can't be updated in time for the cutover — the gateway's error bodies are the only lever that reaches them, and this can deploy ahead of the model-gate flip.
Changes
code: "model_gate", and its message carries a(rate_limit)suffix — a compat shim that routes pre-cutover PostHog Code clients to their usage-limit modal instead of session teardown (documented inline; remove once those builds roll forward).error.message(SDK error strings often surface only the message) and carry the throttle scope aserror.code(billable_credits,user_cost_burst,user_cost_sustained, …), so clients can classify the limit cause.Companion client work: PostHog/code#3485 classifies these bodies into cause-aware billing UX.
How did you test this code?
Automated only: the enforcement-path gate tests now pin the new envelope (
code, the(rate_limit)suffix), the rate-limiting endpoint test pins the message/reason/code shape, and a TestClient-level test pins the gate 403's wire body end-to-end (top-level error envelope withcode: "model_gate"and the(rate_limit)suffix — never{"detail": ...}nesting) through the raise site and the exception-handler unwrap together. All would fail if the shim or codes were dropped. Full llm-gateway suite green locally (1239 passed, 50 skipped, 30 xfailed, 22 xpassed).Automatic notifications
Docs update
None — internal error-body shape.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
PostHog Code session. Part of the usage-based billing cutover client plan: this PR makes gateway billing denials classifiable by both pre- and post-cutover desktop builds.
Created with PostHog Code