nopSolutions/nopCommerce · error · Exception
One page checkout is disabled
Error message
One page checkout is disabled
What it means
Thrown by the OpcSaveBilling action when _orderSettings.OnePageCheckoutEnabled is false, yet a one-page-checkout (OPC) AJAX POST was received. nopCommerce guards every OPC step with this check so a store running multi-page checkout cannot be driven through OPC endpoints. The message is a hardcoded English literal returned inside the JSON error payload { error=1, message }. It indicates a configuration/flow mismatch, not a malformed request.
Source
Thrown at src/Presentation/Nop.Web/Controllers/CheckoutController.cs:1535
[HttpPost]
public virtual async Task<IActionResult> OpcSaveBilling(CheckoutBillingAddressModel model, IFormCollection form)
{
try
{
//validation
if (_orderSettings.CheckoutDisabled)
throw new Exception(await _localizationService.GetResourceAsync("Checkout.Disabled"));
var customer = await _workContext.GetCurrentCustomerAsync();
var store = await _storeContext.GetCurrentStoreAsync();
var cart = await _shoppingCartService.GetShoppingCartAsync(customer, ShoppingCartType.ShoppingCart, store.Id);
if (!cart.Any())
throw new Exception("Your cart is empty");
if (!_orderSettings.OnePageCheckoutEnabled)
throw new Exception("One page checkout is disabled");
if (await _customerService.IsGuestAsync(customer) && !_orderSettings.AnonymousCheckoutAllowed)
throw new Exception("Anonymous checkout is not allowed");
_ = int.TryParse(form["billing_address_id"], out var billingAddressId);
if (billingAddressId > 0)
{
//existing address
var address = await _customerService.GetCustomerAddressAsync(customer.Id, billingAddressId)
?? throw new Exception(await _localizationService.GetResourceAsync("Checkout.Address.NotFound"));
customer.BillingAddressId = address.Id;
await _customerService.UpdateCustomerAsync(customer);
}
else
{
if (await _customerService.IsGuestAsync(customer) && _taxSettings.EuVatEnabled && _taxSettings.EuVatEnabledForGuests)
View on GitHub (pinned to 64bdf2ff08)
Solutions
- Enable OnePageCheckoutEnabled in admin (Order settings) if OPC is the intended flow.
- If OPC is intentionally off, ensure clients never call OpcSaveBilling: redirect the OPC page to the standard BillingAddress action.
- Purge output/CDN cache so browsers stop posting to OPC endpoints after the setting flipped.
- If a custom theme hardcodes OPC AJAX calls, switch it to the multi-page controller flow.
Example fix
// before (admin Order settings) orderSettings.OnePageCheckoutEnabled = false; // after orderSettings.OnePageCheckoutEnabled = true; // enables OpcSaveBilling/OpcSaveShipping/etc.
Defensive patterns
Strategy: validation
Validate before calling
// Client: only render/submit the OPC billing step when OPC is on.
const settings = await fetch('/api/checkout-settings').then(r => r.json());
if (!settings.onePageCheckoutEnabled) { location.href = '/checkout/billingaddress'; return; } Try / catch
// The controller wraps the action in try/catch and returns JSON; handle it.
const res = await fetch('/Checkout/OpcSaveBilling', { method:'POST', body });
const data = await res.json();
if (data.error) {
if (data.message === 'One page checkout is disabled') location.href = '/checkout/billingaddress';
else showUserError(data.message);
} Prevention
- Read OnePageCheckoutEnabled before rendering OPC UI and redirect otherwise.
- Version-bust cached OPC pages on deploy so stale tabs reload.
- Avoid hardcoding OPC AJAX in custom themes; respect the setting.
When it happens
Trigger: A client POSTs to the OpcSaveBilling billing step while _orderSettings.OnePageCheckoutEnabled == false. Typical when an admin disabled OPC but a shopper's stale browser tab still renders the OPC UI, or a custom integration calls OpcSaveBilling directly against a multi-page-checkout store.
Common situations: Admin toggled 'One page checkout enabled' off (Configuration > Order settings); a theme deployed that defaults to standard multi-page checkout; CDN/page cache still serving the old OPC page after the switch; integration tests calling OPC endpoints after a config change.
Related errors
- Anonymous checkout is not allowed
- Selected shipping method can't be loaded
- Checkout.Address.NotFound
- Shipping is not required
- Selected shipping method can't be parsed
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/25fc341a10b2de70.
Report an issue: GitHub.