Payment Intent ID re-used across gateways

Created on 14 May 2025, about 1 month ago

Problem/Motivation

If you have two Stripe Gateways configured (for example, one Test and one Live), then any stripe_intent from the order will be attempted to be re-used on the other.

Steps to reproduce

1. Create two Stripe Gateways in the Drupal admin. They must either be different Stripe accounts or reference both Live and Test environments of the same account.
2. Create a Payment Intent using the checkout on one gateway
3. Go back, switch to other Payment Gateway
4. Attempt to proceed to review page again
5. Checkout errors as follows:

The website encountered an unexpected error. Try again later.

Drupal\commerce_payment\Exception\InvalidRequestException: Invalid parameters were supplied to Stripe's API. in Drupal\commerce_payment\Exception\PaymentGatewayException::createForPayment() (line 36 of modules/contrib/commerce/modules/payment/src/Exception/PaymentGatewayException.php).
Stripe\Exception\InvalidRequestException::factory('No such payment_intent: 'pi_*********************'; a similar object exists in test mode, but a live mode key was used to make this request.', 404, '{
  "error": {
    "code": "resource_missing",
    "doc_url": "https://stripe.com/docs/error-codes/resource-missing",
    "message": "No such payment_intent: 'pi_*********************'; a similar object exists in test mode, but a live mode key was used to make this request.",
    "param": "intent",
    "request_log_url": "https://dashboard.stripe.com/logs/req_***********************",
    "type": "invalid_request_error"
  }
}
', Array, Object, 'resource_missing', 'intent') (Line: 225)
Stripe\ApiRequestor::_specificAPIError('{
  "error": {
    "code": "resource_missing",
    "doc_url": "https://stripe.com/docs/error-codes/resource-missing",
    "message": "No such payment_intent: 'pi_*********************'; a similar object exists in test mode, but a live mode key was used to make this request.",
    "param": "intent",
    "request_log_url": "https://dashboard.stripe.com/logs/req_*********************",
    "type": "invalid_request_error"
  }
}
', 404, Object, Array, Array) (Line: 187)
Stripe\ApiRequestor->handleErrorResponse('{
  "error": {
    "code": "resource_missing",
    "doc_url": "https://stripe.com/docs/error-codes/resource-missing",
    "message": "No such payment_intent: 'pi_*********************'; a similar object exists in test mode, but a live mode key was used to make this request.",
    "param": "intent",
    "request_log_url": "https://dashboard.stripe.com/logs/req_***********************",
    "type": "invalid_request_error"
  }
}
', 404, Object, Array) (Line: 577)
Stripe\ApiRequestor->_interpretResponse('{
  "error": {
    "code": "resource_missing",
    "doc_url": "https://stripe.com/docs/error-codes/resource-missing",
    "message": "No such payment_intent: 'pi_*********************'; a similar object exists in test mode, but a live mode key was used to make this request.",
    "param": "intent",
    "request_log_url": "https://dashboard.stripe.com/logs/req_*****************",
    "type": "invalid_request_error"
  }
}
', 404, Object) (Line: 135)
Stripe\ApiRequestor->request('get', '/v1/payment_intents/pi_*********************', Array, Array) (Line: 59)
Stripe\ApiResource->refresh() (Line: 163)
Stripe\PaymentIntent::retrieve('pi_*********************') (Line: 1530)
Drupal\commerce_stripe\Plugin\Commerce\PaymentGateway\StripePaymentElement->getStripePaymentIntent('pi_*********************') (Line: 1508)
Drupal\commerce_stripe\Plugin\Commerce\PaymentGateway\StripePaymentElement->getIntent('pi_*********************') (Line: 179)
Drupal\commerce_stripe\Plugin\Commerce\CheckoutPane\StripeReview->buildPaneForm(Array, Object, Array) (Line: 546)
Drupal\commerce_checkout\Plugin\Commerce\CheckoutFlow\CheckoutFlowWithPanesBase->buildForm(Array, Object, 'review')
call_user_func_array(Array, Array) (Line: 536)
Drupal\Core\Form\FormBuilder->retrieveForm('commerce_checkout_flow_multistep_default', Object) (Line: 284)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 224)
Drupal\Core\Form\FormBuilder->getForm(Object, 'review') (Line: 143)
Drupal\commerce_checkout\Controller\CheckoutController->formPage(Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 638)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 121)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 181)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 53)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 116)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 90)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 741)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Proposed resolution

Possibly prefix the data store with the payment method ID.

// Instead of this
$intent_id = $order->getData('stripe_intent');

// Do this
$intent_id = $order->getData($payment_method->id() . '_stripe_intent');
🐛 Bug report
Status

Active

Version

2.0

Component

Code

Created by

🇬🇧United Kingdom mattjones86 🇬🇧 GMT+0

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024