nopSolutions/nopCommerce · warning · NopException

Capture is in {refund.Status} status due to {refund.StatusDe

Error message

Capture is in {refund.Status} status due to {refund.StatusDetails?.Reason}

What it means

Thrown by RefundAsync when PayPal returns status PENDING (with a reason in StatusDetails). A pending refund means PayPal has accepted it but money movement is delayed (e.g. bank-funded), so it is not yet complete. The message is interpolated with refund.Status and refund.StatusDetails?.Reason and surfaced as the Error string.

Source

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

            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
            var refundIds = await _genericAttributeService
                .GetAttributeAsync<List<string>>(nopOrder, PayPalCommerceDefaults.RefundIdAttributeName)
                ?? new();
            if (!refundIds.Contains(refund.Id))
                refundIds.Add(refund.Id);
            await _genericAttributeService.SaveAttributeAsync(nopOrder, PayPalCommerceDefaults.RefundIdAttributeName, refundIds);

            return refund;
        });
    }

    #endregion

    #region Recurring payments

    /// <summary>

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Do not treat the order as refunded yet; record the refund as pending and notify staff.
  2. Poll the PayPal refund resource (or listen for the refund-completed webhook) to confirm completion.
  3. Inform the customer that bank-funded refunds can take several business days to settle.

Example fix

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

// after
var (refund, err) = await _serviceManager.RefundAsync(settings, order, amount);
if (!string.IsNullOrEmpty(err) && refund?.Status?.ToUpper() == RefundStatusType.PENDING.ToString())
{
    MarkOrderRefundPending(order, refund.Id);
    NotifyAdmin($"Refund pending: {err}");
    return;
}
Defensive patterns

Strategy: retry

Try / catch

var (refund, error) = await mgr.RefundAsync(settings, order, amount);
if (!string.IsNullOrEmpty(error) && refund?.Status?.ToUpper() == "PENDING")
{
    MarkOrderRefundPending(order, refund.Id);
    // reconcile later via webhook when status becomes COMPLETED
    return;
}

Prevention

When it happens

Trigger: PayPal returns PENDING because the refund is funded from a bank or echeck; PayPal is performing review/compliance hold on the refund.

Common situations: Refund issued against a capture whose funding source is a bank account (echeck); PayPal risk review; high-value refund under manual processing.

Related errors


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