Troubleshooting
Find the symptom, then the fix. API errors come back as HTTP 400 {"message": "..."} unless noted; validation errors as {"error_type": "zod_validation", "fields": {...}} or {"fields": {...}}.
Checkout and payments
The shopper gets a 404 after paying
The gateway returned to <url>/payment/success or <url>/payment/failed, and that page doesn't exist on the site.
- Add
/payment/success,/payment/failedand/track/[id]at exactly these paths, with the package'sPaymentSuccess,PaymentFailedandOrderTracking(rule 3). urlmust be the site's origin with no path and no trailing slash:window.location.origin. Blanxer appends/payment/successto it as is.- Never hardcode
url(rule 4). A hardcodedworkers.devorigin sends shoppers back to the old host after the custom domain is added.
/payment/success sends the shopper to the home page instead of their order
The success page reads the order id from sessionStorage['checkout_order_id'], which only exists on the origin where the checkout ran.
- Serve the site on one host. Redirect
wwwto the apex (or the reverse) so checkout and success are on the same origin. - Don't clear
sessionStoragein your own code. - A shopper who finished paying on another device or browser has no session there; they land on
/. Their order is fine and the confirmation email links to/track/<id>.
Selected delivery city not found, please try again
The order's customer_address_city doesn't exactly match a place name in the store's delivery table.
- Fill the place select only from
GET /public/delivery_charge/<store_id>. Never type place names into the code. - Send the place name as
customer_address_city, not the address. - The merchant may have renamed a place; the site's cached table is at most a minute old. Reload.
Cash on delivery is not available for the selected delivery location
The order asked for COD at a place where the store turned COD off.
- COD is allowed only when the place's flag is
trueor'Y'. A check like!!codtreats'N'as yes: that is a known bug in the Blanxer-hosted storefront; the package doesn't copy it. - When the shopper changes the place and COD disappears from the list, the selected method must change too (the first available one).
The coupon shows a discount, but the order has none
The order was sent with the coupon code ("coupon": "DASHAIN10"). The server only reads coupon when it is longer than 20 characters (an id), so a code is ignored silently: no discount, no error.
- Send the
_idreturned byPOST /public/coupon(rule 2: use the package's checkout, which does this). - Compare the order response:
total_pricealready has the discount taken off.
Coupon errors
| Message | Cause |
|---|---|
Coupan not found |
No coupon with that exact code in this store. Codes are case-sensitive: the input is upper-cased, but a ?promo= link is sent as written, so ?promo=dashain10 fails for DASHAIN10 |
Coupon not found (at order time) |
The coupon _id sent with the order no longer exists |
Coupon is inactive |
Turned off in Blanxer |
All the available coupons have been used. |
Used up. For a coupon with a usage limit, each successful apply also holds a use for about 12 seconds, so on the last use an order placed right after Apply can fail with this. Wait a few seconds and place it again |
Coupon code not available / Coupon code is expired |
Before its start / after its end |
Coupon is not applicable to any products |
A category coupon and no line in those categories |
Coupon is only applicable for order value above N |
Subtotal + customization + delivery under the minimum |
Only cash on delivery can use this coupon / Only online payment method can use this coupon |
Payment method restriction |
This coupon is not valid for <place> |
Place restriction |
Valid Return URL is required
POST /payment/esewa/init, /payment/khalti/init and /payment/fonepay/init reject http://localhost:3000 as url. Test on http://127.0.0.1:3000, on the OpenNext preview opened via 127.0.0.1, or on the deployed site.
Variant selection required for this product / Either of the selected product has been modified, please add to cart again
- The cart line has no
variant, or a variant_idthat no longer exists (the merchant edited the variants). - Make sure
AddToCartstores the variant_id, not its name. - For old carts: drop the line and ask the shopper to add it again.
Please choose a print for <name>
The product has a required print add-on, and the line has no print_id. The package has no print picker yet, so it can't sell that product. Ask the merchant to make the print optional, or leave the product off the site for now. See Checkout → Print add-on products.
Either of the selected product is already deleted / ... is out of stock
The product is no longer Active, or the stock is lower than the quantity (and it doesn't continue selling). Refresh the cart from the product data.
The last units of an item in your cart are in other shoppers' checkouts right now...
Other shoppers hold the last units while they pay. It clears within the hold time (5 minutes; 2–5 during a flash sale). Show the message as is.
HTTP 429 when placing orders
More than 5 order requests in 10 minutes from one IP for one store. Every request counts, including 0000000000 test orders and failed ones. The body is plain text (Too many requests, please try again later.), not JSON; handle that. If every shopper hits it, orders are being sent from the server (one shared Worker IP for everyone): move the call to the browser (rule 5).
The QR payment never confirms
- The page checks while the tab is visible (every 5 s for Fonepay QR, 10 s for Checkout by Fonepay) and when the shopper returns to it. Ask them to come back to the tab or press "Check payment".
- Never close the QR or release the hold on tab switch; shoppers pay in their banking app with the QR open.
Payment not receivedfrom the check endpoint only means "not yet".
The eSewa page shows an error from api.blanxer.com after the shopper cancels
eSewa sends both success and failure back to the same API endpoint. A return without eSewa's data parameter may end on an API error page instead of /payment/failed. This is on Blanxer's side and is being verified; the order stays Inactive, and the shopper can go back to the site.
Khalti shows an error before redirecting
Khalti's own error text is passed through (for example a minimum amount or a configuration problem). Show it; the merchant may need to fix their Khalti settings in Blanxer. If it reads [object Object], Khalti returned a structured error; check the store's Khalti keys in Blanxer.
Catalog and data
A Draft or POS-only product page is visible
GET /product/public/<store_id>/<slug> also returns non-Active (Draft, Archived) and POS-only products. The page must call notFound() unless status === 'Active' && channel !== 3; the package's getProduct() returns null for them. See Catalog → One product.
A product page shows "Product not found" as an error instead of a 404
An unknown slug is HTTP 400 Product not found, not 404. Catch it and call notFound().
Prices or stock lag behind the dashboard
The site caches data for 60 seconds. The API caches the product lists for up to 1 hour and clears them when the merchant saves products, categories or settings. Orders don't clear it, so stock in lists can lag by up to an hour; the product page itself isn't cached by the API. The checkout always charges the current server price and checks the current stock.
Domain not in use
BLANXER_STORE is wrong. It is the subdomain only (mystore), not mystore.blanxer.io and not the custom-site domain.
Server-side reads fail with Cloudflare error 1010
Public reads have been checked to work from plain fetch, curl and Node. The package sends a normal User-Agent. If a Worker still gets 1010, report it to Blanxer with the time and URL; don't work around it with a proxy.
SEO
The catalog sitemap or product feed links to <sub>.blanxer.io
The site link isn't saved in Blanxer. Call blanxer_set_storefront_url (preview, then { dry_run: false, confirm_token }), or the merchant saves it in BlanxerAPI → Your website. The API uses it on the next request, but HTTP caches (max-age=3600, plus stale-while-revalidate) and the site's own /sitemap-catalog.xml can serve old links for an hour or more.
Search Console says the verification tag is missing
- Check the home page source for
<meta name="google-site-verification" ...>. The site must render the store'smeta_tagsplugin (verificationMetadata(store)). - After
blanxer_set_site_verification, wait about a minute for the API and site caches. - The property in Search Console must be the exact host the site is served on (
https://mystore.com/, notwww.if that redirects).
The shopper got no confirmation email
- With
checkout.receiver_infoon and a sender name filled, the email goes only tosender_email; none is sent when that is empty. - Online orders are emailed only once paid. COD orders are emailed when created.
Confirmation emails link to the wrong site
The email uses the url sent with that order. Orders placed before a domain change keep the old link. Make sure the checkout sends window.location.origin.
Deploy
The Worker is over 3 MiB
The Workers free plan allows 3 MiB compressed. Tell the merchant before deploying, then:
- remove heavy server-side dependencies (whole icon sets, UI kits, date libraries, markdown/PDF tools used on the server);
- keep large libraries out of server components;
- or move to the $5/month Workers paid plan (10 MiB).
See Deploy → Worker size.
wrangler deploys to the wrong Cloudflare account
Run npx wrangler whoami. If it's not the merchant's account, npx wrangler logout, then npx wrangler login and have the merchant sign in. With several accounts, set CLOUDFLARE_ACCOUNT_ID.
Images
Images too big / the image budget fails
Every file in public/ must be ≤ 300 KB and ≤ 2560 px wide, as AVIF/WebP, rendered with next/image and a size. Re-run npx blanxer-storefront images with the right export width for the slot (hero 2560, banner 1600, card 800). Never commit originals. Product photos belong in Blanxer, loaded through blanxerImageLoader. See Images and speed.
npx blanxer-storefront check failures
| Failure | Fix |
|---|---|
Missing route /checkout, /payment/success, /payment/failed or /track/[id] |
Add it at that exact path with the package component |
| Secret found | Remove it from code, .env and the build. No key is ever needed (rule 6) |
/customer/auth or /customer/account call, or a login/account/wishlist/rewards page |
Remove it (rule 7). Only /customer/stock-alert is allowed |
| Order or payment call outside the browser | Move it into a client component; no server actions or route handlers for orders, coupons, payments, holds or stock alerts (rule 5) |
| Image budget | See above |
| No image marked as main (warning) | Add preload to each page's main (LCP) image. See Images and speed |
| Lighthouse under 90 / LCP over 2.5 s | See Images and speed → When the check fails |
Agents read this page at /api-docs/troubleshooting.md · Edit on GitHub