{"id":19008730,"date":"2026-09-01T15:32:23","date_gmt":"2026-09-01T15:32:23","guid":{"rendered":"https:\/\/wordpress.org\/support\/topic\/fatal-error-at-checkout-when-tokenization-nonce-is-missing\/"},"modified":"2026-09-01T15:32:23","modified_gmt":"2026-09-01T15:32:23","slug":"fatal-error-at-checkout-when-tokenization-nonce-is-missing","status":"publish","type":"topic","link":"https:\/\/wordpress.org\/support\/topic\/fatal-error-at-checkout-when-tokenization-nonce-is-missing\/","title":{"rendered":"Fatal error at checkout when tokenization nonce is missing"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Plugin version: 1.7.7<br \/>WooCommerce: 11.0.1<br \/>WordPress: 7.1<br \/>PHP: 8.3.33<br \/>Host: SiteGround<br \/>Checkout: classic shortcode (not blocks)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is closely related to two earlier reports that were both closed without a fix:<\/p>\n\n\n\n<ul>\n<li><a href=\"https:\/\/wordpress.org\/support\/topic\/argument-2-passed-to-api-gatewayapi-php-on-line-405-in\/\">&#8220;Argument 2 passed to API\/GatewayAPI.php on line 405 in&#8221; (Feb 2024)<\/a><\/li>\n\n\n\n<li>&#8220;PHP crash is back, Argument #2 ($nonce) must be of type string, null given&#8221; (closed Jan 2024)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Both of those originated from <code>add_payment_method()<\/code> \u2014 a customer saving a card in My Account. <strong>Mine is from <code>process_payment()<\/code> during a live checkout<\/strong>, which is a different entry point with a worse outcome: the customer sees WordPress&#8217;s critical error screen instead of a payment failure message, and the sale is lost.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>What happened<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A customer attempted to place a $799 order. Three attempts in 67 seconds, all three producing an uncaught TypeError and a white screen. The customer abandoned checkout and contacted us by email. The order was left in a failed state with no gateway response recorded against it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PHP Warning:  Undefined property: stdClass::$nonce in ...\/godaddy-payments\/src\/API\/GatewayAPI.php on line 410\nPHP Fatal error:  Uncaught TypeError: GoDaddy\\WooCommerce\\Poynt\\API\\Cards\\TokenizeRequest::__construct(): Argument #2 ($nonce) must be of type string, null given, called in ...\/godaddy-payments\/src\/API\/GatewayAPI.php on line 410 and defined in ...\/godaddy-payments\/src\/API\/Cards\/TokenizeRequest.php:31\nStack trace:\n#0 ...\/godaddy-payments\/src\/API\/GatewayAPI.php(410): TokenizeRequest-&gt;__construct('4abdefa4-99e2-4...', NULL)\n#1 ...\/godaddy-payments\/src\/Gateways\/CreditCardGateway.php(1196): GatewayAPI-&gt;tokenize_payment_method(Object(Order))\n#2 ...\/skyverge\/wc-plugin-framework\/woocommerce\/payment-gateway\/class-sv-wc-payment-gateway-direct.php(860): CreditCardGateway-&gt;do_credit_card_transaction(Object(Order))\n#3 ...\/class-sv-wc-payment-gateway-direct.php(388): SV_WC_Payment_Gateway_Direct-&gt;do_transaction(Object(Order))\n#4 ...\/woocommerce\/includes\/class-wc-checkout.php(1157): SV_WC_Payment_Gateway_Direct-&gt;process_payment(12345)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Diagnosis<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The warning immediately preceding the fatal is the actual cause. <code>$order-&gt;payment<\/code> is a dynamic stdClass the plugin populates from the submitted checkout form, and <code>-&gt;nonce<\/code> holds the token generated client-side by the Poynt Collect SDK. In this session the browser never populated that field, so the property was undefined, resolved to <code>null<\/code>, and was passed straight into a constructor typed <code>string<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">GatewayAPI.php line 410 in 1.7.7:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$request = new TokenizeRequest($this-&gt;getBusinessId(), $order-&gt;payment-&gt;nonce);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The root cause is browser-side and I can&#8217;t reproduce it \u2014 same as both previous reporters, which I believe is why those threads stalled. Likely candidates are an extension or network filter blocking the SDK, or a browser the SDK doesn&#8217;t fully support. That part may well be unfixable from the plugin&#8217;s side.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>But the failure mode is fixable, and that&#8217;s the more important half.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is no guard between an empty nonce and the constructor. A condition the plugin cannot control produces an uncaught fatal in the middle of <code>process_payment()<\/code>, which means:<\/p>\n\n\n\n<ul>\n<li>The customer sees a WordPress critical error page, not a payment error<\/li>\n\n\n\n<li>The order is left with no gateway note explaining anything<\/li>\n\n\n\n<li>Nothing is written to the WooCommerce gateway log<\/li>\n\n\n\n<li>The customer has no indication that retrying might help, and no cart or form state is preserved<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A missing nonce is functionally a failed tokenization. It should be handled like any other payment failure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Suggested patch<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In <code>GatewayAPI::tokenize_payment_method()<\/code>, immediately before line 410:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$nonce = $order-&gt;payment-&gt;nonce ?? null;\n\nif (!is_string($nonce) || $nonce === '') {\n    throw new SV_WC_Payment_Gateway_Exception(\n        'Payment nonce missing from checkout request; card was not tokenized in the browser.'\n    );\n}\n\n$request = new TokenizeRequest($this-&gt;getBusinessId(), $nonce);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">(With the appropriate <code>use<\/code> statement for the version-namespaced framework exception class.)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The framework already catches <code>SV_WC_Payment_Gateway_Exception<\/code> inside <code>process_payment()<\/code> and converts it into a standard declined-payment flow: order marked failed with a note, customer-facing notice, checkout page preserved with the customer&#8217;s details intact. So this guard converts a site-crash into an ordinary retryable failure with no other changes required.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A complementary improvement would be checking for the nonce in the gateway&#8217;s <code>validate_fields()<\/code>, so the customer is stopped before order creation rather than after \u2014 but the guard above is the minimum needed to stop the fatal.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>One environmental note that may or may not be relevant<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The SkyVerge framework actually executing on my install is <code>v5_15_12<\/code>, loaded out of <code>woocommerce-customer-order-csv-export\/vendor\/<\/code> rather than the copy bundled with this plugin. I understand that&#8217;s the framework&#8217;s normal highest-version-wins behavior, but flagging it in case the version drift matters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Context on frequency<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is rare, not systemic. Over the same 21-day window the store took 41 orders, 30 completed normally, and the other failures were ordinary AVS mismatches and issuer declines with clean gateway responses recorded in the order notes. So this isn&#8217;t a misconfiguration on my end \u2014 it&#8217;s one edge case that happens to fail catastrophically instead of gracefully.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Given this is now the third independent report of the same null across two different code paths since 2022, I&#8217;d ask that the guard be added even if the browser-side cause can&#8217;t be tracked down. Merchants shouldn&#8217;t lose sales to a white screen when a declined-card message would do.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Happy to provide anything further. Gateway debug logging is now enabled on my install, so if it recurs I&#8217;ll have the Poynt-side request\/response to add.<\/p>\n","protected":false},"template":"","class_list":["post-19008730","topic","type-topic","status-publish","hentry","topic-tag-checkout","topic-tag-fatal-error","topic-tag-nonce"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/topic\/19008730","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/topic"}],"about":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/types\/topic"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/topic\/19008730\/revisions"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/media?parent=19008730"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}