fix(api): map billing errors to actionable codes instead of internal - #1851
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Coverage Report for CI Build 30980108222Coverage increased (+0.04%) to 47.604%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
1f8a5bd to
f664d5f
Compare
f664d5f to
e0788f5
Compare
4c5a2a4 to
b03f655
Compare
rohilsurana
left a comment
There was a problem hiding this comment.
Reviewed with the rest of the stack. The mapping table is sensible, the mechanical rewrite kept every context string (spot checked), and the test table is thorough: redaction shapes, test-mode ids, and caller-supplied coupon codes are all covered. Promoting already subscribed to the plan to a sentinel with already_exists is a nice touch, and the UpdateProduct refactor keeps the ErrInvalidDetail to invalid_argument path intact.
One real concern about what ends up in server logs, and two smaller points, all inline.
Also checked BillingWebhookCallback: it now answers the webhook sender with 412/503 instead of 500 for provider problems. Stripe retries on any non-2xx, so retry behavior does not change.
rohilsurana
left a comment
There was a problem hiding this comment.
LGTM overall. Please look at the logging comment on mapBillingError before merge.
b03f655 to
25d5aa8
Compare
Billing handlers used a bare CodeInternal for every unrecognized error, so account-state problems looked like Frontier bugs to the caller. All billing handlers now fall back to a shared mapBillingError: - provider record missing -> failed_precondition, "billing account is no longer linked to the payment provider" - payment failures -> failed_precondition with the provider's message - provider rate limits and outages -> unavailable - plan change in progress, pending dues, subscription gone on the provider -> failed_precondition - everything else -> internal, as before Fixes #1836. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- pass the provider's message through for resource-missing errors so a missing coupon or payment method isn't reported as an unlinked account - map customer not-found to not_found instead of internal - name the already-subscribed checkout error and map it to already_exists - map product and feature not-found to not_found Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Provider messages passed to the caller keep their text but hide provider-generated object ids: a deleted customer reads as "No such customer: 'cus_*****'". Caller-supplied values like coupon codes don't match the id shape and stay intact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cs_test_/cs_live_ checkout session ids escaped the mask because of the mode infix, and charge (ch_) ids were not in the prefix list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review fixes on the error mapper: - mapped errors are logged with full detail (handler context, provider request id) before the clean error goes to the caller — the caller error is all the logger interceptor sees, so without this the org and method context would vanish from server logs for exactly these cases - the id mask now matches the general shape of provider ids instead of an allowlist of prefixes, so an object type we haven't listed cannot leak its id - the resource-missing fallback uses the same message as the translated path instead of a second text that guessed the missing object Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
25d5aa8 to
e947ba0
Compare
What
Adds one shared fallback,
mapBillingError, and uses it in place of the ~87 bareconnect.CodeInternalwraps across the billing handlers:billing.ErrProviderResourceMissingfailed_preconditionbilling.ErrPaymentFailedfailed_preconditionbilling.ErrProviderUnavailableunavailablesubscription.ErrSubscriptionOnProviderNotFoundfailed_preconditionsubscription.ErrPhaseIsUpdatingfailed_preconditioncustomer.ErrExistingAccountWithPendingDuesfailed_preconditioninternalThe existing specific mappings in the handlers (
errors.Isladders for not-found, invalid-argument, and so on) are untouched; only the final fallback changes. The rewrite was done withgofmt -r, so every call keeps its context string.Why
internalshould mean "a bug in Frontier". Today it also covers ordinary account states the caller can fix — the clearest case beingGetUpcomingInvoicereturninginternalforever when the org's Stripe customer was deleted (#1835). With this change the caller learns whose move it is: fix the account, retry later, or report a bug.Fixes #1836. Stack: translator (#1849) → services (#1850) → this PR.
🤖 Generated with Claude Code