Wei-Shaw/sub2api · error

payment.airwallexLoadFailed

Error message

payment.airwallexLoadFailed

What it means

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.

Solutions

  1. Allow js.airwallex.com (and its CDN) in the page CSP script-src/connect-src.
  2. Pin the Airwallex web SDK version explicitly and verify the loaded bundle exposes window.Airwallex().payments.
  3. Check the network tab for blocked/failed airwallex requests and disable ad blockers on the checkout page.
  4. Validate the intent is still active (not expired) before loading the SDK; refresh the payment session if not.

Example fix

// before
if (!result.payments) {
  throw new Error(t('payment.airwallexLoadFailed'))
}
const redirectResult = result.payments.redirectToCheckout(checkoutOptions)

// after
if (!result.payments || typeof result.payments.redirectToCheckout !== 'function') {
  throw new Error(t('payment.airwallexLoadFailed'))
}
try {
  const redirectResult = await result.payments.redirectToCheckout(checkoutOptions)
  if (typeof redirectResult === 'string' && redirectResult) window.location.assign(redirectResult)
} catch (e) {
  errorMessage.value = e instanceof Error && e.message ? e.message : t('payment.airwallexLoadFailed')
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify the SDK exposes the payments module with the method you need before checkout:
const aw = await loadAirwallex({ locale: checkoutLocale });
if (!aw?.payments || typeof aw.payments.redirectToCheckout !== 'function') {
  errorMessage.value = t('payment.airwallexLoadFailed');
  return;
}

Type guard

interface AirwallexPayments { redirectToCheckout(opts: Record<string, unknown>): unknown }
function hasPaymentsModule(aw: unknown): aw is { payments: AirwallexPayments } {
  return !!aw && typeof (aw as any)?.payments?.redirectToCheckout === 'function';
}

Try / catch

try {
  const aw = await loadAirwallex({ locale });
  if (!hasPaymentsModule(aw)) throw new Error(t('payment.airwallexLoadFailed'));
  await aw.payments.redirectToCheckout(checkoutOptions);
} catch (err) {
  loading.value = false;
  errorMessage.value = err instanceof Error && err.message ? err.message : t('payment.airwallexLoadFailed');
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15). Data as JSON: /api/errors/f69f68d6d7a98585. Report an issue: GitHub.

Appendix: source

Thrown at frontend/src/views/user/AirwallexPaymentView.vue:119

  try {
    const airwallex = await import('@airwallex/components-sdk')
    const result = await airwallex.init({
      env: snapshot.paymentEnv === 'prod' ? 'prod' : 'demo',
      enabledElements: ['payments'],
      locale: checkoutLocale,
    })

    loading.value = false
    const checkoutOptions = {
      intent_id: snapshot.intentId,
      client_secret: snapshot.clientSecret,
      currency: snapshot.currency || 'CNY',
      country_code: snapshot.countryCode || 'CN',
      successUrl: buildSuccessUrl(snapshot),
    }
    if (!result.payments) {
      throw new Error(t('payment.airwallexLoadFailed'))
    }
    const redirectResult = result.payments.redirectToCheckout(checkoutOptions)

    if (typeof redirectResult === 'string' && redirectResult) {
      window.location.assign(redirectResult)
    }
  } catch (err: unknown) {
    loading.value = false
    errorMessage.value = err instanceof Error && err.message
      ? err.message
      : t('payment.airwallexLoadFailed')
  }
})
</script>

View on GitHub (pinned to 073e92d171)