dotnet/eShop · error · OrderingDomainException

Is not possible to change the order status from {OrderStatus

Error message

Is not possible to change the order status from {OrderStatus} to {orderStatusToChange}.

What it means

Thrown by Order.StatusChangeException, invoked from SetShippedStatus (when the current status is not Paid) and SetCancelledStatus (when the current status is Paid or Shipped). It guards the order state machine: only defined transitions are allowed (e.g. Paid -> Shipped, AwaitingValidation -> Cancelled). An OrderingDomainException signals an illegal state transition was requested.

Source

Thrown at src/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs:182

            var itemsStockRejectedDescription = string.Join(", ", itemsStockRejectedProductNames);
            Description = $"The product items don't have stock: ({itemsStockRejectedDescription}).";
        }
    }

    private void AddOrderStartedDomainEvent(string userId, string userName, int cardTypeId, string cardNumber,
            string cardSecurityNumber, string cardHolderName, DateTime cardExpiration)
    {
        var orderStartedDomainEvent = new OrderStartedDomainEvent(this, userId, userName, cardTypeId,
                                                                    cardNumber, cardSecurityNumber,
                                                                    cardHolderName, cardExpiration);

        this.AddDomainEvent(orderStartedDomainEvent);
    }

    private void StatusChangeException(OrderStatus orderStatusToChange)
    {
        throw new OrderingDomainException($"Is not possible to change the order status from {OrderStatus} to {orderStatusToChange}.");
    }

    public decimal GetTotal() => _orderItems.Sum(o => o.Units * o.UnitPrice);
}

View on GitHub (pinned to 9b4f9434f4)

Solutions

  1. Before invoking SetShippedStatus, confirm OrderStatus == OrderStatus.Paid; before SetCancelledStatus, confirm it is not Paid or Shipped — branch or reject otherwise.
  2. Make command handlers idempotent and ordered: ensure the SetPaidStatus event has been applied before a ship command is dispatched (use a saga with a wait-on-payment step).
  3. On an illegal-transition OrderingDomainException, re-read the aggregate and either no-op if already in the target state or surface a conflict to the caller rather than retrying unchanged.
  4. Add optimistic concurrency so a stale aggregate version cannot apply a transition against an outdated OrderStatus.

Example fix

// before
order.SetShippedStatus();

// after
if (order.OrderStatus != OrderStatus.Paid) {
    throw new InvalidOperationException($"Cannot ship: order is {order.OrderStatus}");
}
order.SetShippedStatus();
Defensive patterns

Strategy: validation

Validate before calling

if (order.OrderStatus != OrderStatus.Paid) return Error($"Cannot ship from {order.OrderStatus}");
order.SetShippedStatus();

Type guard

static bool CanShip(Order o) => o.OrderStatus == OrderStatus.Paid;
static bool CanCancel(Order o) => o.OrderStatus != OrderStatus.Paid && o.OrderStatus != OrderStatus.Shipped;

Try / catch

try {
    order.SetShippedStatus();
} catch (OrderingDomainException ex) when (ex.Message.Contains("Is not possible to change")) {
    // re-read aggregate; no-op if already in target state, else report conflict
}

Prevention

When it happens

Trigger: Calling order.SetShippedStatus() while OrderStatus is anything other than Paid (Submitted/AwaitingValidation/StockConfirmed/Cancelled). Calling order.SetCancelledStatus() on an order that is already Paid or Shipped. Triggered by out-of-order command processing, replayed commands, or UI/staff actions that assume a later state than the aggregate is actually in.

Common situations: Duplicate or reordered domain commands (e.g. shipping command arriving before the paid event was applied); a saga/orchestrator firing the ship step without confirming payment succeeded; manual admin tool issuing Cancel on an already-paid order; integration tests not resetting order state between steps.

Related errors


AI-assisted analysis of dotnet/eShop@9b4f9434f4 (2026-08-13). Data as JSON: /api/errors/06b24e4efd1f1735. Report an issue: GitHub.