payloadcms/payload · error · Error

Unknown error initiating payment

Error message

Unknown error initiating payment

What it means

Thrown by the catch block at the end of Stripe confirmOrder when the caught error is not an Error instance (e.g. a string, plain object, or null thrown deep in a dependency). It is the fallback branch of error instanceof Error ? error.message : 'Unknown error initiating payment'. The original error is logged via payload.logger.error before rethrowing, so the underlying cause is in the logs even though the thrown message is generic.

Source

Thrown at packages/plugin-ecommerce/src/payments/adapters/stripe/confirmOrder.ts:144

        id: transaction.id,
        collection: transactionsSlug,
        data: {
          order: order.id,
          status: 'succeeded',
        },
        req,
      })

      return {
        message: 'Payment initiated successfully',
        orderID: order.id,
        transactionID: transaction.id,
        ...(order.accessToken ? { accessToken: order.accessToken } : {}),
      }
    } catch (error) {
      payload.logger.error({ err: error, msg: 'Error confirming order with Stripe' })

      throw new Error(error instanceof Error ? error.message : 'Unknown error initiating payment')
    }
  }

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Check the Payload logs for the err field logged immediately before this throw to find the real cause.
  2. Reproduce in isolation and inspect typeof error and error.constructor.name in a debugger.
  3. Upgrade/downgrade the stripe package to a version whose errors are Error instances.
  4. Wrap third-party calls so they always reject with Error objects (e.g. catch and re-throw new Error(String(e))).

Example fix

// before: a dependency throws a non-Error
throw 'bad value' // surfaces as 'Unknown error initiating payment'
// after: normalize to Error
throw new Error('bad value')
Defensive patterns

Strategy: try-catch

Validate before calling

// Wrap third-party calls so they always reject with Error instances
async function safeCall<T>(fn: () => Promise<T>): Promise<T> {
  try {
    return await fn()
  } catch (e) {
    if (e instanceof Error) throw e
    throw new Error(typeof e === 'string' ? e : JSON.stringify(e))
  }
}

Type guard

export function isErrorLike(e: unknown): e is Error {
  return e instanceof Error || (typeof e === 'object' && e !== null && typeof (e as { message?: unknown }).message === 'string')
}

Try / catch

try {
  await payments.confirmOrder({ data: { paymentIntentID } })
} catch (err) {
  if (err instanceof Error && err.message === 'Unknown error initiating payment') {
    // inspect server logs for the original err object logged just before this throw
    return { ok: false, reason: 'unknown-confirm-error', checkLogs: true }
  }
  throw err
}

Prevention

When it happens

Trigger: Any non-Error value thrown inside confirmOrder's try block — for example a third-party SDK that throws a string, a JSON.parse on malformed metadata that throws in a wrapper, or a network layer that rejects with a plain object. Any Error-typed thrown value surfaces its own message instead; only non-Error throws reach this branch.

Common situations: Stripe SDK downgrade/upgrade introducing a non-Error rejection; a custom hook in the order-create pipeline throwing a string; JSON.parse on truncated Stripe metadata throwing a SyntaxError (that one is an Error and would surface its own message — but a wrapping library could convert it); unhandled promise rejections from misconfigured fetch polyfills.

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/5e90353e6e5f7acd. Report an issue: GitHub.