{"record":{"id":"f69f68d6d7a98585","repo":"Wei-Shaw/sub2api","slug":"payment-airwallexloadfailed","errorCode":null,"errorMessage":"payment.airwallexLoadFailed","messagePattern":"payment\\.airwallexLoadFailed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/views/user/AirwallexPaymentView.vue","lineNumber":119,"sourceCode":"\n  try {\n    const airwallex = await import('@airwallex/components-sdk')\n    const result = await airwallex.init({\n      env: snapshot.paymentEnv === 'prod' ? 'prod' : 'demo',\n      enabledElements: ['payments'],\n      locale: checkoutLocale,\n    })\n\n    loading.value = false\n    const checkoutOptions = {\n      intent_id: snapshot.intentId,\n      client_secret: snapshot.clientSecret,\n      currency: snapshot.currency || 'CNY',\n      country_code: snapshot.countryCode || 'CN',\n      successUrl: buildSuccessUrl(snapshot),\n    }\n    if (!result.payments) {\n      throw new Error(t('payment.airwallexLoadFailed'))\n    }\n    const redirectResult = result.payments.redirectToCheckout(checkoutOptions)\n\n    if (typeof redirectResult === 'string' && redirectResult) {\n      window.location.assign(redirectResult)\n    }\n  } catch (err: unknown) {\n    loading.value = false\n    errorMessage.value = err instanceof Error && err.message\n      ? err.message\n      : t('payment.airwallexLoadFailed')\n  }\n})\n</script>\n","sourceCodeStart":101,"sourceCodeEnd":134,"githubUrl":"https://github.com/Wei-Shaw/sub2api/blob/073e92d17178a1ccdb0a27017f572f10c9c7ab62/frontend/src/views/user/AirwallexPaymentView.vue#L101-L134","documentation":"In frontend/src/views/user/AirwallexPaymentView.vue:119, the code awaits loadAirwallex({ locale }) (the Airwallex Web SDK), then checks result.payments — the payments module needed for redirectToCheckout. If the SDK loaded but initialized without a payments module (wrong package entry, blocked script, init failure swallowed), it throws the localized 'payment.airwallexLoadFailed'. The same key is the generic fallback in the catch block.","triggerScenarios":"Airwallex SDK script loads partially or an older/different bundle is served that lacks the payments namespace; loadAirwallex resolves with an incomplete object because the script was blocked by a CSP without script-src allowing js.airwallex.com; network interception (ad blocker) loading a stub; SDK version drift where payments moved to a submodule import.","commonSituations":"Strict Content-Security-Policy blocking the third-party SDK; regional network filtering of airwallex domains (common in mainland China); bundler resolving a mock/outdated airwallex package; the checkout intent (intentId/clientSecret) expired so init degrades.","solutions":["Allow js.airwallex.com (and its CDN) in the page CSP script-src/connect-src.","Pin the Airwallex web SDK version explicitly and verify the loaded bundle exposes window.Airwallex().payments.","Check the network tab for blocked/failed airwallex requests and disable ad blockers on the checkout page.","Validate the intent is still active (not expired) before loading the SDK; refresh the payment session if not."],"exampleFix":"// before\nif (!result.payments) {\n  throw new Error(t('payment.airwallexLoadFailed'))\n}\nconst redirectResult = result.payments.redirectToCheckout(checkoutOptions)\n\n// after\nif (!result.payments || typeof result.payments.redirectToCheckout !== 'function') {\n  throw new Error(t('payment.airwallexLoadFailed'))\n}\ntry {\n  const redirectResult = await result.payments.redirectToCheckout(checkoutOptions)\n  if (typeof redirectResult === 'string' && redirectResult) window.location.assign(redirectResult)\n} catch (e) {\n  errorMessage.value = e instanceof Error && e.message ? e.message : t('payment.airwallexLoadFailed')\n}","handlingStrategy":"type-guard","validationCode":"// Verify the SDK exposes the payments module with the method you need before checkout:\nconst aw = await loadAirwallex({ locale: checkoutLocale });\nif (!aw?.payments || typeof aw.payments.redirectToCheckout !== 'function') {\n  errorMessage.value = t('payment.airwallexLoadFailed');\n  return;\n}","typeGuard":"interface AirwallexPayments { redirectToCheckout(opts: Record<string, unknown>): unknown }\nfunction hasPaymentsModule(aw: unknown): aw is { payments: AirwallexPayments } {\n  return !!aw && typeof (aw as any)?.payments?.redirectToCheckout === 'function';\n}","tryCatchPattern":"try {\n  const aw = await loadAirwallex({ locale });\n  if (!hasPaymentsModule(aw)) throw new Error(t('payment.airwallexLoadFailed'));\n  await aw.payments.redirectToCheckout(checkoutOptions);\n} catch (err) {\n  loading.value = false;\n  errorMessage.value = err instanceof Error && err.message ? err.message : t('payment.airwallexLoadFailed');\n}","preventionTips":["Allow js.airwallex.com in CSP script-src/connect-src","Pin the Airwallex web SDK version and assert window.Airwallex().payments exists after load","Check the intent is still active before loading the SDK; refresh expired payment sessions","Warn users when a blocker/extension prevented the SDK from fully loading"],"tags":["payments","airwallex","sdk","csp","checkout","frontend"],"backgroundTag":null,"analyzedSha":"073e92d17178a1ccdb0a27017f572f10c9c7ab62","analyzedAt":"2026-08-15T14:33:00.750Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}