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
- Do not treat the order as refunded yet; record the refund as pending and notify staff.
- Poll the PayPal refund resource (or listen for the refund-completed webhook) to confirm completion.
- 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
- Handle PayPal refund-completed webhooks to finalize pending refunds.
- Treat PENDING as unsettled, not as success.
- Tell customers bank-funded refunds take days to settle.
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
- The refund was cancelled
- The refund could not be processed
- Capture ID not set
- Shopping cart has no recurring items
- Setup token not set
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/90d54cefb2d39f36.
Report an issue: GitHub.