nopSolutions/nopCommerce · error · Exception
Checkout.Address.NotFound
Error message
Checkout.Address.NotFound
What it means
Thrown by OpcSaveBilling after the ?? null-coalescing operator when GetCustomerAddressAsync(customer.Id, billingAddressId) returns null. The client supplied a billing_address_id > 0 that does not map to an address owned by that customer. The message is the localized resource key 'Checkout.Address.NotFound' resolved through ILocalizationService. It signals stale/invalid address selection data, not a server error.
Source
Thrown at src/Presentation/Nop.Web/Controllers/CheckoutController.cs:1546
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)
{
var warning = await SaveCustomerVatNumberAsync(model.VatNumber, customer);
if (!string.IsNullOrEmpty(warning))
ModelState.AddModelError("", warning);
}
//new address
var newAddress = model.BillingNewAddress;
//custom address attributes
var customAttributes = await _addressAttributeParser.ParseCustomAttributesAsync(form, NopCommonDefaults.AddressAttributeControlName);
View on GitHub (pinned to 64bdf2ff08)
Solutions
- Refresh the address dropdown from the customer's actual address book before submit.
- Drop billing_address_id from the post and submit as a new (ShippingNewAddress/BillingNewAddress) address.
- Verify the address id passed is one returned by GetAddressesByCustomerId for that customer.
- If migrating, remap legacy address IDs to new ones.
Example fix
// before: posting a stale id
form["billing_address_id"] = oldDeletedAddressId;
// after: validate against the address book before posting
var mine = await _customerService.GetAddressesByCustomerIdAsync(customer.Id);
if (!mine.Any(a => a.Id == billingAddressId)) { /* send 0 to create a new address */ } Defensive patterns
Strategy: validation
Validate before calling
// Validate the chosen address id belongs to the customer before posting. var owned = (await _customerService.GetAddressesByCustomerIdAsync(customer.Id)).Select(a => a.Id); if (!owned.Contains(billingAddressId)) billingAddressId = 0; // fall back to new address
Try / catch
const data = await res.json();
if (data.error && /address/i.test(data.message)) {
await refreshAddressBook(); // re-pull the customer's addresses
selectFirstAddress();
} Prevention
- Render the address dropdown from GetAddressesByCustomerIdAsync at render time.
- After an address is deleted elsewhere, invalidate the dropdown.
- Treat a missing id as 'create new address' rather than posting a stale id.
When it happens
Trigger: Client posts form['billing_address_id'] = <positive id> for an address that the customer does not own or that no longer exists (deleted, belongs to another account, post-migration ID mismatch). Happens when a stored address list is out of sync with the form.
Common situations: Customer deleted the address in another tab but the dropdown still lists it; address book migrated with new IDs while the page cache holds old IDs; address shared across merged accounts; tampered/curled request with an arbitrary id.
Related errors
- {ModelState errors joined by ', '}
- One page checkout is disabled
- Anonymous checkout is not allowed
- 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/1e5158c5aaa6c07b.
Report an issue: GitHub.