Skip to content

Fix null Stripe invoice crash in upgrade preview#387

Merged
simonhamp merged 1 commit into
mainfrom
fix-stripe-invoice-null
May 19, 2026
Merged

Fix null Stripe invoice crash in upgrade preview#387
simonhamp merged 1 commit into
mainfrom
fix-stripe-invoice-null

Conversation

@simonhamp
Copy link
Copy Markdown
Member

@simonhamp simonhamp commented May 19, 2026

Summary

Fixes #63: Error: Call to a member function asStripeInvoice() on null thrown from app/Livewire/MobilePricing.php:121 when a user opens the upgrade modal.

Root cause

Cashier's Subscription::previewInvoice() returns null when Stripe has no upcoming invoice (canceled subscription, missing customer, etc.). The existing try/catch (\Exception) didn't catch the resulting \Error (PHP Error doesn't extend Exception), so it surfaced as a 500.

Fix

  • Added a null guard after previewInvoice() so the existing "Unable to load pricing preview" fallback UI renders gracefully.
  • Widened the catch from \Exception to \Throwable as a defense-in-depth for any future PHP errors on this path.
  • Added a degraded preview branch for canceled-but-in-grace subscribers (most importantly EAP folks who legitimately want to upgrade). For that state, Stripe returns no upcoming invoice, so we skip the Stripe call entirely and build the preview from configured plan pricing. The modal shows the new charge with a "(pro-rated)" tag and a line clarifying that the remaining time will be credited at checkout. Stripe still computes the actual proration server-side at swapAndInvoice time, so the charge stays correct.

Test plan

  • New test reproduces the exact production error when the fix is reverted (preview_upgrade_sets_preview_to_null_when_stripe_has_no_upcoming_invoice).
  • New tests cover the degraded-preview path (canceled-in-grace user gets a preview without touching Stripe; EAP customers see the EAP yearly price; modal renders the pending-proration copy).
  • All 30 MobilePricingTest cases pass; broader Livewire/Stripe test sweep (185 tests) passes.
  • Manually verify in staging: open the upgrade modal as a canceled-in-grace EAP user.

🤖 Generated with Claude Code

…eled-in-grace subscribers

Cashier's Subscription::previewInvoice() returns null when Stripe has no
upcoming invoice (e.g. canceled subscription in grace period) — the call
to asStripeInvoice() on null threw an Error that the \Exception catch
didn't catch, surfacing as a 500.

Add a null guard, widen the catch to \Throwable, and for canceled-but-
in-grace users skip Stripe entirely and show a degraded preview based on
configured plan price. Stripe still computes proration correctly at
swapAndInvoice time.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@simonhamp simonhamp marked this pull request as ready for review May 19, 2026 16:14
@simonhamp simonhamp merged commit d00591c into main May 19, 2026
2 checks passed
@simonhamp simonhamp deleted the fix-stripe-invoice-null branch May 19, 2026 16:15
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