{"record":{"id":"362a210657965807","repo":"nopSolutions/nopCommerce","slug":"next-payment-date-could-not-be-calculated","errorCode":null,"errorMessage":"Next payment date could not be calculated","messagePattern":"Next payment date could not be calculated","errorType":"exception","errorClass":"NopException","httpStatus":null,"severity":"warning","filePath":"src/Libraries/Nop.Services/Orders/OrderProcessingService.cs","lineNumber":1905,"sourceCode":"    /// The task result contains the collection of errors\r\n    /// </returns>\r\n    public virtual async Task<IEnumerable<string>> ProcessNextRecurringPaymentAsync(RecurringPayment recurringPayment, ProcessPaymentResult paymentResult = null)\r\n    {\r\n        ArgumentNullException.ThrowIfNull(recurringPayment);\r\n\r\n        try\r\n        {\r\n            if (!recurringPayment.IsActive)\r\n                throw new NopException(\"Recurring payment is not active\");\r\n\r\n            var initialOrder = await _orderService.GetOrderByIdAsync(recurringPayment.InitialOrderId)\r\n                               ?? throw new NopException(\"Initial order could not be loaded\");\r\n\r\n            var customer = await _customerService.GetCustomerByIdAsync(initialOrder.CustomerId)\r\n                           ?? throw new NopException(\"Customer could not be loaded\");\r\n\r\n            if (await GetNextPaymentDateAsync(recurringPayment) is null)\r\n                throw new NopException(\"Next payment date could not be calculated\");\r\n\r\n            //payment info\r\n            var processPaymentRequest = new ProcessPaymentRequest\r\n            {\r\n                StoreId = initialOrder.StoreId,\r\n                CustomerId = customer.Id,\r\n                OrderGuid = Guid.NewGuid(),\r\n                InitialOrder = initialOrder,\r\n                RecurringCycleLength = recurringPayment.CycleLength,\r\n                RecurringCyclePeriod = recurringPayment.CyclePeriod,\r\n                RecurringTotalCycles = recurringPayment.TotalCycles\r\n            };\r\n\r\n            processPaymentRequest.CustomValues.FillByXml(initialOrder.CustomValuesXml);\r\n\r\n            //prepare order details\r\n            var details = await PrepareRecurringOrderDetailsAsync(processPaymentRequest);\r\n\r","sourceCodeStart":1887,"sourceCodeEnd":1923,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Libraries/Nop.Services/Orders/OrderProcessingService.cs#L1887-L1923","documentation":"Thrown in ProcessNextRecurringPaymentAsync when GetNextPaymentDateAsync(recurringPayment) returns null. nopCommerce computes the next billing date from CycleLength/CyclePeriod/StartDate/CyclesRemaining; if that math yields no valid future date (e.g. all cycles exhausted, or the start date is invalid), it refuses to charge the customer.","triggerScenarios":"A recurring payment whose cycle configuration produces no next date: total cycles already completed, CycleLength <= 0, CyclePeriod unset, or StartDateUtc in an unparseable state. The recurring task picks it up but cannot determine when to bill.","commonSituations":"Subscription reached its total cycle count but IsActive was not flipped to false; misconfigured recurring product (zero cycle length); timezone/UTC date corruption in the order seed.","solutions":["Compare CyclesProcessed against TotalCycles - if equal, set IsActive=false (subscription complete).","Correct the recurring payment's CycleLength/CyclePeriod/StartDateUtc if malformed.","Guard the recurring task to skip payments whose next date is null."],"exampleFix":"// before\nvar errors = await _orderProcessingService.ProcessNextRecurringPaymentAsync(recurringPayment);\n\n// after\nif (await _orderProcessingService.GetNextPaymentDateAsync(recurringPayment) is null)\n{\n    recurringPayment.IsActive = false; // cycles exhausted\n    await _orderService.UpdateRecurringPaymentAsync(recurringPayment);\n    continue;\n}\nvar errors = await _orderProcessingService.ProcessNextRecurringPaymentAsync(recurringPayment);","handlingStrategy":"validation","validationCode":"if (await _orderProcessingService.GetNextPaymentDateAsync(recurringPayment) is null)\n{\n    // cycles exhausted or misconfigured - mark complete\n    recurringPayment.IsActive = false;\n    await _orderService.UpdateRecurringPaymentAsync(recurringPayment);\n    _logger.LogInformation(\"Recurring payment {Id} has no next payment date - deactivating.\",\n        recurringPayment.Id);\n    return Array.Empty<string>();\n}\n\nreturn await _orderProcessingService.ProcessNextRecurringPaymentAsync(recurringPayment);","typeGuard":"Task<bool> HasNextCycleAsync(RecurringPayment rp)\n    => _orderProcessingService.GetNextPaymentDateAsync(rp).ContinueWith(t => t.Result is not null);","tryCatchPattern":"try\n{\n    var errors = await _orderProcessingService.ProcessNextRecurringPaymentAsync(recurringPayment);\n}\ncatch (NopException ex) when (ex.Message == \"Next payment date could not be calculated\")\n{\n    recurringPayment.IsActive = false;\n    await _orderService.UpdateRecurringPaymentAsync(recurringPayment);\n    _logger.LogWarning(ex, \"Recurring payment {Id} has invalid cycle config\", recurringPayment.Id);\n}","preventionTips":["Pre-check GetNextPaymentDateAsync before processing each recurring payment.","Validate CycleLength > 0 and CyclePeriod is set when configuring recurring products.","Flip IsActive=false when CyclesProcessed reaches TotalCycles so exhausted subscriptions are not retried."],"tags":["recurring","subscription","date-calculation","lifecycle","nopcommerce"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}