nopSolutions/nopCommerce · error · NopException
Cannot do refund for order.
Error message
Cannot do refund for order.
What it means
Thrown by OrderProcessingService.RefundAsync when CanRefundAsync(order) returns false. A full online refund is allowed only when OrderTotal > 0, RefundedAmount == 0 (no prior partial refunds), PaymentStatus == Paid, and the payment method supports refund (SupportRefundAsync). It blocks refunding zero-total orders, orders already partially refunded, or orders whose gateway cannot refund.
Source
Thrown at src/Libraries/Nop.Services/Orders/OrderProcessingService.cs:2648
return true;
return false;
}
/// <summary>
/// Refunds an order (from admin panel)
/// </summary>
/// <param name="order">Order</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains a list of errors; empty list if no errors
/// </returns>
public virtual async Task<IList<string>> RefundAsync(Order order)
{
ArgumentNullException.ThrowIfNull(order);
if (!await CanRefundAsync(order))
throw new NopException("Cannot do refund for order.");
var request = new RefundPaymentRequest();
RefundPaymentResult result = null;
try
{
request.Order = order;
request.AmountToRefund = order.OrderTotal;
request.IsPartialRefund = false;
result = await _paymentService.RefundAsync(request);
if (result.Success)
{
//total amount refunded
var totalAmountRefunded = order.RefundedAmount + request.AmountToRefund;
//update order info
order.RefundedAmount = totalAmountRefunded;
order.PaymentStatus = result.NewPaymentStatus;
await _orderService.UpdateOrderAsync(order);
View on GitHub (pinned to 64bdf2ff08)
Solutions
- Guard with: if (!await _orderProcessingService.CanRefundAsync(order)) return; and inspect why it is ineligible.
- If RefundedAmount > 0, use PartiallyRefundAsync(order, remainingAmount) instead of RefundAsync.
- Verify _paymentService.SupportRefundAsync(order.PaymentMethodSystemName); install a payment plugin that supports refund, or use the offline refund flow.
- Confirm PaymentStatus == Paid before offering the refund action.
Example fix
// before
var errors = await _orderProcessingService.RefundAsync(order);
// after
if (!await _orderProcessingService.CanRefundAsync(order))
{
if (order.RefundedAmount > decimal.Zero)
return await _orderProcessingService.PartiallyRefundAsync(order, order.OrderTotal - order.RefundedAmount);
return new[] { "Refund is not available for this order." };
}
var errors = await _orderProcessingService.RefundAsync(order); Defensive patterns
Strategy: validation
Validate before calling
if (!await _orderProcessingService.CanRefundAsync(order))
{
if (order.RefundedAmount > decimal.Zero)
return await _orderProcessingService.PartiallyRefundAsync(order, order.OrderTotal - order.RefundedAmount);
return Array.Empty<string>();
}
return await _orderProcessingService.RefundAsync(order); Prevention
- If RefundedAmount > 0, use PartiallyRefundAsync, not RefundAsync.
- Confirm PaymentStatus == Paid and the gateway supports refund.
- Skip refund for zero-total orders.
When it happens
Trigger: Calling RefundAsync when: OrderTotal == 0; RefundedAmount > 0 (use partial refund instead); PaymentStatus != Paid; or the payment method does not support refund. Typical from admin 'Refund' on an ineligible order.
Common situations: Trying a full refund after a partial refund was already issued (must use PartiallyRefundAsync); payment gateway plugin not supporting refund; order not actually Paid (still Pending/Authorized); free order with zero total.
Related errors
- Cannot do capture for order.
- You can't refund this order
- Cannot do partial refund for order.
- Cannot do void for order.
- You can't mark this order as paid
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/888c7df1a34f25fb.
Report an issue: GitHub.