Skip to content
ThemesIonic — home
WooCommerce

Fixing "Invalid payment method" in WooCommerce

WooCommerce says a payment method is invalid when the gateway the shopper picked is no longer in the list of available gateways by the time the order is submitted. Here is how to find out what removed it.

5 min read intermediate

WooCommerce shows "Invalid payment method." when the gateway ID posted with the order is not in the list of available gateways at the moment of validation. In the classic checkout, WC_Checkout::validate_checkout() calls WC()->payment_gateways->get_available_payment_gateways(). If the posted payment_method is not a key in that array, it adds the error and never calls the gateway at all. The list is rebuilt on every request, so the method the shopper clicked can be available when the page renders and missing a second later when they press Place order.

How the available list is built

get_available_payment_gateways() does three things, and any of them can remove a gateway:

  1. It asks each gateway is_available(). The base implementation requires the gateway to be enabled and, if a maximum amount is set, the order total to be under it. Most gateways override this with their own rules: supported currencies, countries, minimum totals, API keys being present.
  2. It applies the woocommerce_available_payment_gateways filter. This is where plugins and snippets hide gateways by role, cart contents or shipping method.
  3. It drops anything that is not a WC_Payment_Gateway object. A filter that returns gateway IDs or arrays instead of objects silently empties the list.

So "Invalid payment method" is never about the payment provider rejecting a card. The order did not reach the provider. Gateway errors such as declined cards come later, from the gateway's own process_payment(), with their own wording.

Where the message comes from

Screen Trigger
Classic checkout Posted gateway not in the available list
Pay for order (/checkout/order-pay/…) No gateway posted, or the posted one is not available
My Account › Payment methods Saved token missing, not owned by the user, or nonce failed
Block checkout Different text: "… is not available for this order—please choose a different payment method"

Knowing the screen halves the search. The rest of this article is about the first two rows.

Cause 1: a rule that changes between render and submit

When the shopper presses Place order, WooCommerce first updates the session with the submitted address and shipping method and recalculates totals. Only then does it validate. Any availability rule that depends on those values is therefore evaluated against the submitted data, which may differ from what the page showed.

The built-in example is Enable for shipping methods on Cash on delivery, Direct bank transfer and Check payments. Suppose COD is limited to local delivery. The shopper selects local delivery, picks COD, then switches to flat rate. Normally the checkout refreshes the payment list. But a theme or optimisation plugin that breaks the update_checkout AJAX refresh leaves COD on screen. Validation then rejects it. The same applies to Accept for virtual orders when the cart changes from physical to virtual.

Test it by opening the browser's Network tab and changing the shipping method. A ?wc-ajax=update_order_review request should fire and return new payment HTML. If nothing fires, fix the refresh; the payment rule is working correctly. Checkout not working covers JavaScript errors that stop these requests.

Cause 2: a custom filter that assumes the wrong context

Snippets on woocommerce_available_payment_gateways are the most common source of this error in custom stores. Three patterns break:

add_filter( 'woocommerce_available_payment_gateways', function ( $gateways ) {
	// Breaks on the pay-for-order page: the cart is empty there.
	if ( WC()->cart && WC()->cart->get_total( 'edit' ) < 50 ) {
		unset( $gateways['bacs'] );
	}
	return $gateways;
} );
  • Reading the cart on the pay-for-order page. That page pays an existing order, and the cart is usually empty, so a cart-based rule gives a different answer than it did at checkout. Check is_checkout_pay_page() and read the order instead.
  • Reading request data that is not there on submit. A rule based on a query string, a cookie set by JavaScript or a $_GET value from the page URL works when the page renders and is missing from the ?wc-ajax=checkout request that submits the order.
  • Returning the wrong shape. The filter must return the same array of gateway objects, keyed by ID. Returning array_keys() or a rebuilt array of IDs removes everything.

To confirm a filter is responsible, log the list at the point of validation:

add_action( 'woocommerce_after_checkout_validation', function ( $data, $errors ) {
	wc_get_logger()->info(
		wp_json_encode( array(
			'posted'    => $data['payment_method'],
			'available' => array_keys( WC()->payment_gateways->get_available_payment_gateways() ),
		) ),
		array( 'source' => 'ti-gateways' )
	);
}, 10, 2 );

Read it under WooCommerce › Status › Logs. If the posted ID is missing from available, deactivate snippets and plugins until it reappears.

Cause 3: limits inside the gateway

A maximum order amount, an unsupported currency (common with multi-currency plugins switching currency mid-session), a country restriction or missing API credentials all make is_available() return false. Each is invisible to the shopper. The settings screen still says enabled. Check the gateway's own settings and its log, which most gateways write under the same Status › Logs screen. A store using several currencies should test each one, since some gateways only accept a subset.

Cause 4: a cached checkout

If the checkout page is cached, shoppers can see a payment list rendered for another visitor's cart, or a list from before you changed gateway settings. They pick a gateway that is not available for their own order, and validation correctly rejects it. Exclude cart and checkout from every cache layer, as described in excluding pages from cache.

Common mistakes

  • Hiding gateways with CSS. The radio button stays in the form and can still be posted, and a hidden gateway that is also unavailable produces exactly this error.
  • Checking only the settings screen. Availability is computed per order; reproduce with the same address, shipping method, currency and cart total.
  • Treating it as a gateway outage. No request reached the provider, so their status page will not explain it. If the gateway itself is failing, see payment complete for how successful payments are recorded, and compare.

Verify

  1. Reproduce with the customer's cart, address and shipping method in a private window.
  2. Change the shipping method and confirm the payment list refreshes.
  3. Check the log snippet's output: the posted gateway is in the available list.
  4. Place a test order on the pay-for-order page as well, if you send payment links from the admin.

Frequently asked

Enabled is only the first test. The gateway's own is_available() can also refuse based on order total, shipping method, virtual products or currency, and any code on woocommerce_available_payment_gateways can remove it afterwards. Validation uses the final list, not the settings screen.
No. The block checkout goes through the Store API and returns "[gateway] is not available for this order—please choose a different payment method", or "No payment method provided" when none was sent. The cause is the same availability list.
No. On that screen the message appears when deleting or setting a default saved card fails, because the token does not exist, belongs to another user, or the link's nonce has expired. Reloading the page and trying again usually clears it.

Related guides