nopSolutions/nopCommerce · error · NopException

The refund could not be processed

Error message

The refund could not be processed

What it means

Thrown by RefundAsync when PayPal returns a refund resource with status FAILED. This means PayPal declined to process the refund, typically for funds, account, or restriction reasons, after the API call itself succeeded. It is reported as the Error string and the refund id is not recorded.

Source

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

            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
            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

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Ensure the PayPal account has sufficient balance in the capture currency to cover the refund.
  2. Check the PayPal dashboard for account limitations and resolve them, then retry.
  3. Confirm the capture has not already been fully refunded before retrying.

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))
{
    NotifyAdmin($"Refund failed: {err}. Verify PayPal balance and account status.");
    return; // leave order un-refunded so it can be retried
}
Defensive patterns

Strategy: retry

Try / catch

var (refund, error) = await mgr.RefundAsync(settings, order, amount);
if (!string.IsNullOrEmpty(error))
{
    NotifyAdmin($"Refund failed: {error}. Check PayPal balance/account status.");
    // leave refundable; retry once the account is in good standing
    return;
}

Prevention

When it happens

Trigger: PayPal declines the refund: insufficient merchant PayPal balance; account limited/restricted; the capture was already fully refunded; currency/amount constraints rejected it.

Common situations: Merchant PayPal balance insufficient to fund the refund; account under limitation; duplicate refund attempt after a prior one already consumed the capture.

Related errors


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