Skip to content

Studio: say what Stripe refused, instead of "something went wrong" - #14

Merged
visualfart merged 1 commit into
mainfrom
fix/stripe-errors
Sep 30, 2026
Merged

visualfart merged 1 commit into
mainfrom
fix/stripe-errors

Conversation

@visualfart

Copy link
Copy Markdown
Owner

What was wrong

Pressing Upgrade returned a bare 500. A StripeError thrown anywhere except the founding-coupon retry fell through to the generic handler, so the owner saw "Something went wrong on our side" and the reason was only in the Worker's logs.

Stripe's own message now comes back: a refusal as 400 with its code and param, an outage as 502. Stripe's messages name the object that was asked for, not the key that asked, so nothing secret travels with them.

What it found

I ran Studio locally against Stripe test mode and did a real checkout. The new message said it immediately:

Invalid line_items[0]: the product tax code is missing. Set the product's tax_code field to an eligible product tax code. Product tax code is required for Managed Payments, which is enabled by default on your account.

Not the mode mismatch I had assumed. The products had no tax_code, and Managed Payments requires one. All four products (test and live, Pro and Team) are now txcd_10103001 — Software as a service (SaaS), business use.

Then the whole loop ran

With the tax code set, a full test-mode purchase went through on localhost:

  • Checkout opened at $4.40 — $8.00, the founding coupon's 50% off, plus $0.40 GST
  • Paid with 4242 4242 4242 4242
  • stripe listen forwarded 16 events, every one answered 200
  • The workspace row: plan=pro, plan_status=active, billing_interval=month, seats=1, period_end=2026-10-30, customer stored

So checkout, the webhook, the signature check and the plan update all work against real Stripe.

Checked

86 tests pass, including two new ones: a Stripe refusal returns 400 with the message, code and param; a Stripe outage returns 502.

🤖 Generated with Claude Code

A StripeError thrown outside the founding-coupon retry reached the generic
handler, so an owner pressing Upgrade with a price the key can't see — a test
price under a live key, say — got a blank 500 and no way to tell a mode
mismatch from an outage.

Stripe's own message now comes back: a refusal as 400 with its code and param,
an outage as 502. Stripe's messages name the object that was asked for, not the
key that asked, so nothing secret travels with them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@visualfart
visualfart merged commit 3fb86c4 into main Sep 30, 2026
1 check passed
@visualfart
visualfart deleted the fix/stripe-errors branch September 30, 2026 20:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant