nopSolutions/nopCommerce · error · NopException

Not supported cycle period

Error message

Not supported cycle period

What it means

Thrown by OrderProcessingService in the CalculateNextPaymentDate path when recurringPayment.CyclePeriod does not match any of the known RecurringProductCyclePeriod values (Days, Weeks, Months, Years). It is an enum-exhaustiveness guard (the default arm of a switch expression). Hitting it means the persisted CyclePeriod value is outside the defined enum range, which should be impossible under normal data entry and signals corruption or an unsupported value.

Source

Thrown at src/Libraries/Nop.Services/Orders/OrderProcessingService.cs:3282

            return null;

        var historyCollection = await _orderService.GetRecurringPaymentHistoryAsync(recurringPayment);
        if (historyCollection.Count >= recurringPayment.TotalCycles)
            return null;

        //result
        DateTime? result = null;

        //calculate next payment date
        if (historyCollection.Any())
        {
            result = recurringPayment.CyclePeriod switch
            {
                RecurringProductCyclePeriod.Days => recurringPayment.StartDateUtc.AddDays((double)recurringPayment.CycleLength * historyCollection.Count),
                RecurringProductCyclePeriod.Weeks => recurringPayment.StartDateUtc.AddDays((double)(7 * recurringPayment.CycleLength) * historyCollection.Count),
                RecurringProductCyclePeriod.Months => recurringPayment.StartDateUtc.AddMonths(recurringPayment.CycleLength * historyCollection.Count),
                RecurringProductCyclePeriod.Years => recurringPayment.StartDateUtc.AddYears(recurringPayment.CycleLength * historyCollection.Count),
                _ => throw new NopException("Not supported cycle period"),
            };
        }
        else
        {
            if (recurringPayment.TotalCycles > 0)
                result = recurringPayment.StartDateUtc;
        }

        return result;
    }

    /// <summary>
    /// Gets the cycles remaining
    /// </summary>
    /// <param name="recurringPayment">Recurring payment</param>
    /// <returns>A task that represents the asynchronous operation</returns>
    public virtual async Task<int> GetCyclesRemainingAsync(RecurringPayment recurringPayment)
    {

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Find and repair the offending RecurringPayment row: validate CyclePeriod is within the defined enum range (0-3 by default) and correct it.
  2. Add input validation when creating recurring payments to reject out-of-range CyclePeriod values before persistence.
  3. If you extended the enum, update this switch to handle the new members.
  4. Catch NopException around recurring-payment processing and log the recurringPayment.Id for triage.

Example fix

// before (creating a recurring payment)
recurringPayment.CyclePeriod = (RecurringProductCyclePeriod)someInt;

// after
if (!Enum.IsDefined(typeof(RecurringProductCyclePeriod), someInt))
    throw new ArgumentException($"Invalid cycle period {someInt}");
recurringPayment.CyclePeriod = (RecurringProductCyclePeriod)someInt;
Defensive patterns

Strategy: type-guard

Validate before calling

if (!Enum.IsDefined(typeof(RecurringProductCyclePeriod), recurringPayment.CyclePeriod))
    throw new ArgumentException($"Invalid CyclePeriod {recurringPayment.CyclePeriod} on recurring payment {recurringPayment.Id}");

var next = await _orderProcessingService.GetNextPaymentDateAsync(recurringPayment);

Type guard

static bool IsValidCyclePeriod(RecurringProductCyclePeriod p) =>
    p == RecurringProductCyclePeriod.Days ||
    p == RecurringProductCyclePeriod.Weeks ||
    p == RecurringProductCyclePeriod.Months ||
    p == RecurringProductCyclePeriod.Years;

Prevention

When it happens

Trigger: A RecurringPayment whose CyclePeriod is set to an integer that does not map to Days/Weeks/Months/Years, evaluated while computing the next payment date (historyCollection.Any()). Reachable via custom code that casts an arbitrary int to RecurringProductCyclePeriod, a corrupted row, or an enum value removed/renamed between versions.

Common situations: A migration or manual SQL that wrote an out-of-range CyclePeriod; a custom plugin casting an invalid int; a version upgrade where an enum member was removed but old rows still reference it; tests seeding bad data.

Related errors


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