antiwork/gumroad · error · Subscription::UpdateFailed

replacement_card.errors.messages[:base].first

Error message

replacement_card.errors.messages[:base].first

What it means

After a chargeable is built, UpdaterService calls CreditCard.create(chargeable, card_data_handling_mode, logged_in_user). CreditCard.create does not raise on failure — it returns a CreditCard whose errors are populated. When :base errors are present, the first base message is raised as Subscription::UpdateFailed and the whole update transaction rolls back. The base message is buyer-facing (typically instructing a different card).

Source

Thrown at app/services/subscription/updater_service.rb:125

        end

        # Update card if necessary
        unless use_existing_card?
          had_saved_card = subscription.credit_card.present?

          # (a) Get chargeable. Return if error
          error_message = get_chargeable
          if error_message.present?
            logger.info("SubscriptionUpdater: Error fetching chargeable for subscription #{subscription.external_id}: #{error_message}")
            raise Subscription::UpdateFailed, error_message
          end

          # (b) Create new credit card. Return if error.
          replacement_card = CreditCard.create(chargeable, card_data_handling_mode, logged_in_user)

          unless replacement_card.errors.empty?
            logger.info("SubscriptionUpdater: Error creating new credit card for subscription #{subscription.external_id}: #{replacement_card.errors.full_messages}")
            raise Subscription::UpdateFailed, replacement_card.errors.messages[:base].first
          end

          if indian_card_mandate_validation_required?(replacement_card)
            # A plan update builds its replacement purchase before mandate validation. Keep the
            # new card available for that build, but persist it only after validation succeeds.
            subscription.credit_card = replacement_card
          else
            associate_replacement_card!(replacement_card, had_saved_card:, **validate_indian_card_mandate!(replacement_card))
            replacement_card = nil
          end
        end

        if !same_plan_and_price? || (is_resubscribing && discount_changed) || seller_price_changed
          self.new_purchase = subscription.update_current_plan!(
            new_variants: variants,
            new_price: price,
            new_quantity: params[:quantity],
            perceived_price_cents: purchase_perceived_price_cents(original_discount),

View on GitHub (pinned to afeacbd394)

Solutions

  1. Read the logged line "SubscriptionUpdater: Error creating new credit card" — replacement_card.errors.full_messages names the exact base error(s).
  2. Retry with a freshly entered card; token reuse after a double-submit is the most common cause.
  3. If the base error looks like a processor/API failure rather than a card problem, verify charge processor health and credentials, then retry.

Example fix

# before: assuming CreditCard.create always succeeds
card = CreditCard.create(chargeable, card_data_handling_mode, user)
subscription.credit_card = card

# after: mirror the service's guard (updater_service.rb:123)
raise Subscription::UpdateFailed, card.errors.messages[:base].first unless card.errors.empty?
Defensive patterns

Strategy: fallback

Try / catch

begin
  result = Subscription::UpdaterService.new(subscription:, params:, logged_in_user:, gumroad_guid:, remote_ip:).perform
rescue Subscription::UpdateFailed => e
  result = { success: false, error_message: e.message } # keep the old card; prompt re-entry
end
render_error(result[:error_message]) unless result[:success]

Prevention

When it happens

Trigger: A new card is supplied on a membership update (use_existing_card? false) and the charge processor rejects saving the payment method: Stripe customer/card record creation fails, the instrument data in the chargeable fails CreditCard :base validations, or the token passed to card creation has already been consumed.

Common situations: Double-submit of the card form consuming the token on the first attempt, PayPal billing agreement not yet confirmed when card creation runs, charge processor outage mid-flow, or a chargeable built for a processor the merchant account no longer accepts.

Related errors


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/1cc8769791af1e6b. Report an issue: GitHub.