nopSolutions/nopCommerce · error · NopException

Capture ID not set

Error message

Capture ID not set

What it means

Thrown by RefundAsync when nopOrder.CaptureTransactionId is null or empty. A refund targets a specific captured payment, so PayPal requires the capture resource id; without it the CreateRefundRequest.CaptureId cannot be set. This guard fires before any API call and is surfaced as the Error string.

Source

Thrown at src/Plugins/Nop.Plugin.Payments.PayPalCommerce/Services/PayPalCommerceServiceManager.cs:2566

    /// <param name="nopOrder">Order</param>
    /// <param name="amount">Amount to refund; pass null to refund the full captured amount</param>
    /// <returns>
    /// A task that represents the asynchronous operation
    /// The task result contains the refund details; error message if exists
    /// </returns>
    public async Task<(Refund Refund, string Error)> RefundAsync(PayPalCommerceSettings settings, NopOrder nopOrder, decimal? amount = null)
    {
        return await HandleFunctionAsync(async () =>
        {
            if (!IsConfigured(settings))
                throw new NopException("Plugin not configured");

            var currencyCode = (await _currencyService.GetCurrencyByIdAsync(_currencySettings.PrimaryStoreCurrencyId))?.CurrencyCode;
            if (string.IsNullOrEmpty(currencyCode))
                throw new NopException("Primary store currency not set");

            if (string.IsNullOrEmpty(nopOrder.CaptureTransactionId))
                throw new NopException("Capture ID not set");

            var request = new CreateRefundRequest
            {
                CaptureId = nopOrder.CaptureTransactionId,
                Amount = amount.HasValue ? PrepareMoney(amount.Value, currencyCode) : null
            };
            var refund = await _httpClient.RequestAsync<CreateRefundRequest, CreateRefundResponse>(request, settings);

            if (refund.Status?.ToUpper() == RefundStatusType.CANCELLED.ToString())
                throw new NopException("The refund was cancelled");

            if (refund.Status?.ToUpper() == RefundStatusType.FAILED.ToString())
                throw new NopException("The refund could not be processed");

            if (refund.Status?.ToUpper() == RefundStatusType.PENDING.ToString())
                throw new NopException($"Capture is in {refund.Status} status due to {refund.StatusDetails?.Reason}");

            //save id to avoid double refund

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Confirm the order was actually captured and that order.CaptureTransactionId is populated.
  2. Guard with !string.IsNullOrEmpty(nopOrder.CaptureTransactionId) before calling RefundAsync.
  3. If the order is Authorize-only, void it (VoidAsync) instead of refunding.

Example fix

// before
var (refund, err) = await _serviceManager.RefundAsync(settings, order, amount);

// after
if (string.IsNullOrEmpty(order.CaptureTransactionId))
{
    NotifyError("Order has no captured payment to refund");
    return;
}
var (refund, err) = await _serviceManager.RefundAsync(settings, order, amount);
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrEmpty(order.CaptureTransactionId))
    return; // no capture to refund

Type guard

static string CaptureId(NopOrder o) =>
    string.IsNullOrEmpty(o?.CaptureTransactionId) ? null : o.CaptureTransactionId;

Try / catch

var (refund, error) = await mgr.RefundAsync(settings, order, amount);
if (!string.IsNullOrEmpty(error))
    NotifyError(error);

Prevention

When it happens

Trigger: Refunding an order that was authorized but never captured; the capture step ran but failed to persist CaptureTransactionId on the order; attempting to refund a manually-created or Authorize-only order.

Common situations: Payment mode set to Authorize (not Capture), so there is no capture to refund; capture failed mid-flow and the order was left without a capture id; order was placed through a different payment method and CaptureTransactionId was never set.

Related errors


AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13). Data as JSON: /api/errors/439034809cbcaf9a. Report an issue: GitHub.