Skip to content

feat(llm-gateway): add billing-denial error codes and legacy-client shim - #71343

Merged
adboio merged 2 commits into
masterfrom
posthog-code/llm-gateway-billing-error-codes
Jul 15, 2026
Merged

feat(llm-gateway): add billing-denial error codes and legacy-client shim#71343
adboio merged 2 commits into
masterfrom
posthog-code/llm-gateway-billing-error-codes

Conversation

@adboio

@adboio adboio commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

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 detail string. 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

  • 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 — 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).
  • Throttle 429s repeat the reason in error.message (SDK error strings often surface only the message) and carry the throttle scope as error.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 with code: "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

  • Publish to changelog?
  • Alert Sales and Marketing teams?

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

@github-actions

Copy link
Copy Markdown
Contributor

Hey @adboio! 👋

It looks like your git author email on this PR isn't your @posthog.com address (adambowker98@gmail.com). Since you're on the PostHog team, it's worth pointing your local git author email at your @posthog.com address. Why it matters:

  • Consistent work identity in git history — internal tooling that attributes commits to team members keys off your @posthog.com address.
  • Keeps team contributions easy to tell apart from external community ones when scanning history.

You can fix it for this repo with:

git config user.email "you@posthog.com"

Or set it globally with git config --global user.email "you@posthog.com". No need to redo this PR — just a nudge for next time. 🙂

@adboio
adboio requested review from a team July 15, 2026 20:57
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

adboio commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@adboio
adboio marked this pull request as ready for review July 15, 2026 21:03
@greptile-apps

greptile-apps Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

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
@adboio adboio added the stamphog Request AI approval (no full review) label Jul 15, 2026 — with Graphite App
@trunk-io

trunk-io Bot commented Jul 15, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

@adboio
adboio merged commit 28cb8c2 into master Jul 15, 2026
207 of 215 checks passed

adboio commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Merge activity

@adboio
adboio deleted the posthog-code/llm-gateway-billing-error-codes branch July 15, 2026 21:52
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 15, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-15 22:32 UTC Run
prod-us ✅ Deployed 2026-07-15 22:50 UTC Run
prod-eu ✅ Deployed 2026-07-15 22:48 UTC Run

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

Labels

stamphog Request AI approval (no full review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants