Documentation Index
Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt
Use this file to discover all available pages before exploring further.
Error Handling
App Bridge errors fall into three categories:- Transport errors — the host never responds. The SDK rejects with a timeout after 10 seconds.
- Host-reported errors — the host runs your action but the underlying
operation fails. The SDK rejects with an
Errorcarrying the host’s reason string. - User-cancellation — the host returns a successful response whose
payload signals the user dismissed the prompt. These are not thrown;
they resolve normally with a discriminator field (
cancelled: true, emptyselection, etc.). Treat them as a normal branch.
How errors flow through dispatchAndWait
The wire format for an error response is:
error is present on the response, the SDK rejects the promise with
new Error(response.error) so callers can use a standard try / catch:
Timeouts
dispatchAndWait rejects with Error('App Bridge: timeout waiting for <ACTION> response') after 10 000 ms if the host never responds.
The timeout is hard-coded; you cannot tune it per call. Three things
commonly cause a timeout:
- Action is unsupported on the current host. The admin host doesn’t
wire
CART_LINES_CHANGE; the checkout host doesn’t wireRESOURCE_PICKER_OPEN; the post-purchase host doesn’t wireMODAL_OPEN. Use the host capability table in each host’s reference page to feature-gate calls. - The host hasn’t mounted yet. Checkout extensions sometimes
dispatch before
<CheckoutExtensionSlot>finishes mounting. Wait forBRIDGE_PINGonce before issuing real calls. - A typo in the action name. Action names are case-sensitive and
the host silently drops unknown names.
'TOAST_SHO'will time out ten seconds later — there is no synchronous “unknown action” error.
USER_FETCH,
CONFIG_FETCH, ENVIRONMENT_FETCH, CART_GET, etc.) where a missed
response means stale state.
Subscription errors
app.subscribe(action, callback) forwards the host’s error string as
the second argument:
payload ({}) and
silently render an empty cart. Always destructure (payload, error).
Per-action failure modes
Toast
Toast.create(app, { … }).dispatch() is fire-and-forget — it doesn’t
return a promise, so transport failures are invisible. If the toast
must succeed (regulatory notice, payment receipt), use
dispatchAndWait('TOAST_SHOW', …) and surface a fallback in catch.
The admin host reads payload.type; the React checkout host reads
payload.variant. The Toast helper sends type; in checkout iframes
build the payload manually.
Modal / ConfirmationModal
action === 'dismissed'). Treat dismissed as a normal
cancel, not an error. A timeout here means the host never opened the
modal at all — usually because the iframe is in a context that doesn’t
support modals (checkout, post-purchase).
Resource Picker
cancelled: true with selection: [] is the user-cancel signal — not an
error. Check the discriminator before treating an empty selection as a
problem:
resourceType for that surface — admin-only
types (order, customer, etc.) on a non-admin host will time out.
Clipboard
Clipboard.write() runs iframe-side and silently falls back to the
legacy document.execCommand('copy') path when the modern API throws
or is unavailable. The promise still resolves either way — there is no
indication to the caller that the legacy path ran.
Clipboard.read() (and the paste() alias) does reject when the
host denies the request — Chrome blocks clipboard-read for cross-
origin iframes, so the SDK delegates to the host, and the host can
reject if the user denies the permission prompt or the focused window
isn’t authorised. Errors arrive as
Error('clipboard read denied') or similar.
Cart (checkout / post-purchase)
Cart.applyCartLinesChange, applyDiscountCodeChange,
applyNoteChange, applyAttributeChange, applyMetafieldChange all
throw when the host’s verify-cart pipeline rejects the mutation. Common
reasons:
- A
cart_transformororder_validationfunction blocks the change. - The merchant’s discount rules reject the code (expired, min-cart not met, mutually exclusive with another active discount).
- The line variant is sold out or no longer purchasable.
new Error('verify-cart blocked: out of stock').
Always wrap cart mutations in try / catch and re-fetch the cart
(CART_GET) on failure so your UI mirrors host state.
removeDiscountCode and addGiftCard are stubbed today — they resolve
with { ok: false, applicable: false } instead of throwing. Inspect
applicable before assuming success.
METAFIELD_CHANGE on the checkout host is reserved for forward
compatibility and currently rejects with error: 'cart metafields not supported yet'.
BuyerJourney
The intercept callback can be sync or async. If it throws, the SDK defaults tobehavior: 'allow' so the buyer is never trapped by a
broken extension. Watch your console — silent intercept failures cause
your business rule to be bypassed.
RestApi
RestApi.fetch() reuses the standard Fetch API — it does not throw
on non-2xx. Inspect response.ok yourself, or use fetchJson() which
rejects on non-2xx with a body-aware message:
'RestApi: host CONFIG_GET did not return apiBase'— the host responded but the payload lacksapiBase. The SDK clears its config cache so the next call retries. Verify the host implementsCONFIG_GET.'App Bridge: timeout waiting for SESSION_TOKEN_REQUEST response'— the host never returned a JWT. Most often happens when the iframe is in a host that doesn’t authenticate apps (checkout, post-purchase).
Intents
Intents.launch() is fire-and-forget — it returns the postMessage id
synchronously and never throws (beyond the empty-target guard).
Intents.launchAndWait() rejects on timeout or when the target doesn’t
resolve:
{ error: '...' } (host could
not resolve the target — typically an unknown handle) or
{ cancelled: true } (user closed the launched modal without
completing).
Session Token
app.getSessionToken() and useSessionToken().getToken() both throw
when the host rejects the JWT request — typically because the API
key / shop combination is invalid. Catch once at the top of your data
layer and surface a “reconnect” CTA:
exp claim, so a
single failure doesn’t trigger a retry storm.
Error reference
| Source | Symptom | Cause | Recovery |
|---|---|---|---|
dispatchAndWait | Error('App Bridge: timeout waiting for X response') | Host doesn’t wire X or hasn’t mounted | Feature-gate, retry once, fall back |
dispatchAndWait | Error('<host reason>') | Host returned error: field | Show user-friendly message |
subscribe(action, cb) | cb(payload, error) with error populated | Host emitted error for the channel | Ignore payload, render fallback |
Modal.dispatch() | resolves with action: 'dismissed' | User closed without clicking | Treat as cancel |
ResourcePicker.dispatch() | resolves with cancelled: true | User closed picker | Treat as cancel |
Clipboard.read() | Error('clipboard read denied') | Permissions Policy or user denial | Prompt user to allow paste |
Cart.apply* | Error('verify-cart blocked: ...') | Function / merchant rule blocked mutation | Re-fetch cart, show reason |
BuyerJourney.intercept callback throws | Defaults to allow | Your code errored | Log + add explicit fallback |
RestApi.fetchJson | Error('RestApi: 4xx ... — <body>') | Backend rejected the request | Inspect status, retry / surface |
app.getSessionToken() | rejects | Host couldn’t sign a JWT | Show reconnect CTA, do not retry |
Patterns
Show toast on transient failure, propagate on persistent
Gracefully degrade when an action isn’t wired
Surface BuyerJourney intercept failures without trapping the buyer
See Also
- Actions Reference — payload + response shapes for every action class.
- App Bridge for Checkout — host capability table for the checkout iframe context.
- Post-Purchase Bridge — the subset
available after
DONE. - React Hooks — hook return shapes including
loading/errorfields.