antiwork/gumroad · error · ChargeProcessorCardError

net_negative_seller_revenue

net_negative_seller_revenue

Error message

The purchase total is too small for us to process. Please add another item to your order or contact the creator.

What it means

Raised as ChargeProcessorCardError (code net_negative_seller_revenue) by StripeIntentChargeRouting.validate_seller_proceeds! before the PaymentIntent is submitted. For a direct (Stripe Connect) account the application fee must not consume the entire charge (seller proceeds >= 0 subunits); for a destination-charge account the transfer must be at least 1 subunit. If amount_cents - amount_for_gumroad_cents falls below that floor, the charge is rejected locally so Stripe never sees an intent with a zero/negative seller amount.

Source

Thrown at app/business/payments/charging/implementations/stripe/stripe_intent_charge_routing.rb:82

      MINIMUM_DIRECT_CHARGE_SELLER_PROCEEDS_CENTS
    elsif destination_charge_account?(merchant_account)
      MINIMUM_DESTINATION_TRANSFER_AMOUNT_CENTS
    else
      return
    end

    seller_amount_cents = amount_cents - amount_for_gumroad_cents
    return if seller_amount_cents >= minimum_seller_proceeds_cents

    ErrorNotifier.notify(
      "Charge rejected before Stripe submit: seller proceeds would be non-positive",
      reference:,
      charge_amount_cents: amount_cents,
      gumroad_amount_cents: amount_for_gumroad_cents,
      seller_amount_cents:,
      currency:
    )
    raise ChargeProcessorCardError.new(PurchaseErrorCode::NET_NEGATIVE_SELLER_REVENUE, SELLER_PROCEEDS_ERROR_MESSAGE)
  end
end

View on GitHub (pinned to afeacbd394)

Solutions

  1. Raise the effective charge total above the fee (buyer adds another item, or the creator raises the price / minimum price above the fee floor) — the message already steers buyers there.
  2. If this fires for legitimate prices, audit the fee computation feeding amount_for_gumroad_cents (fee calculation or rounding bug) using the ErrorNotifier payload (charge_amount_cents, gumroad_amount_cents, seller_amount_cents, currency, reference).
  3. For destination-charge sellers, remember the floor is 1 subunit of the intent's currency, not USD — a 1-subunit JPY total still fails because the fee must leave >= 1 subunit for the transfer.
  4. Do not relax the guard: Stripe itself rejects a destination transfer of 0, so bypassing it only moves the failure downstream to a harder Stripe error.

Example fix

# before: submitting the intent and letting the guard raise
params = StripeIntentChargeRouting.fee_params(merchant_account:, amount_cents: 30, amount_for_gumroad_cents: 30, currency: "usd", reference:)
# after: validate proceeds first and block at the price layer
floor = merchant_account.is_a_stripe_connect_account? ? 0 : 1
raise PriceTooLow if amount_cents - amount_for_gumroad_cents < floor
params = StripeIntentChargeRouting.fee_params(merchant_account:, amount_cents:, amount_for_gumroad_cents:, currency:, reference:)
Defensive patterns

Strategy: validation

Validate before calling

floor = merchant_account.is_a_stripe_connect_account? ? 0 : 1
usable = (amount_cents - amount_for_gumroad_cents) >= floor
raise InvalidCartError, "total too small" unless usable

Prevention

When it happens

Trigger: Calling StripeIntentChargeRouting.fee_params (both client-confirm and server-confirm checkout assemble fees through it) with a tiny amount_cents where the Gumroad fee equals or exceeds the total — e.g. a 30-cent product where the fee is 30+ cents, or a 100%-off-plus-fee combination on a destination-charge seller where the transfer would be 0 subunits.

Common situations: Products priced at the minimum (a few cents/currency subunits) with the fee floor exceeding the price; discounts or pay-what-you-want minimums that drop the total below the fee; zero-decimal or low-subunit currencies (JPY) where a 1-unit total is fully consumed by the fee; miscomputed amount_for_gumroad_cents during fee-model changes.

Related errors


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