{"record":{"id":"7f45c0187a90ba3f","repo":"fullstackhero/dotnet-starter-kit","slug":"operation-requires-invoice-status-expected-but-was-status","errorCode":null,"errorMessage":"Operation requires invoice status {expected} but was {Status}.","messagePattern":"Operation requires invoice status (.+?) but was (.+?)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Modules/Billing/Modules.Billing/Domain/Invoice.cs","lineNumber":174,"sourceCode":"        }\n        Status = InvoiceStatus.Void;\n        VoidedAtUtc = DateTime.UtcNow;\n        if (!string.IsNullOrWhiteSpace(reason))\n        {\n            Notes = string.IsNullOrWhiteSpace(Notes) ? reason : $\"{Notes}; Voided: {reason}\";\n        }\n    }\n\n    public void SetNotes(string? notes)\n    {\n        Notes = notes;\n    }\n\n    private void RequireStatus(InvoiceStatus expected)\n    {\n        if (Status != expected)\n        {\n            throw new InvalidOperationException($\"Operation requires invoice status {expected} but was {Status}.\");\n        }\n    }\n\n    private void RecalculateTotals()\n    {\n        SubtotalAmount = _lineItems.Aggregate(\n            Money.Zero(SubtotalAmount.Currency),\n            (acc, l) => acc.Add(l.Amount));\n    }\n}\n","sourceCodeStart":156,"sourceCodeEnd":185,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Billing/Modules.Billing/Domain/Invoice.cs#L156-L185","documentation":"Invoice.RequireStatus is a private guard used by AddLineItem and Issue: the operation demands the invoice be in exactly the expected status (e.g. Draft) and throws InvalidOperationException otherwise. It enforces that line items are only edited before issuance and that Issue only applies to drafts.","triggerScenarios":"Calling AddLineItem on an Issued/Paid/Void invoice; calling Issue() on an invoice that is not Draft.","commonSituations":"Re-running an invoice-build job against already-issued invoices; editing invoice lines after sending to the customer; replayed integration events applying mutations twice.","solutions":["Only mutate line items while Status is Draft; create a credit/adjustment for issued invoices.","Check Status before calling Issue() or AddLineItem().","Make event handlers idempotent so duplicate events don't re-apply mutations.","Clone a new Draft invoice if changes are needed after issuance."],"exampleFix":"// before\nissuedInvoice.AddLineItem(item); // throws\n\n// after\nif (invoice.Status == InvoiceStatus.Draft)\n{\n    invoice.AddLineItem(item);\n}","handlingStrategy":"validation","validationCode":"if (invoice.Status != InvoiceStatus.Draft) throw new InvalidOperationException(\"Invoice lines are immutable after issue.\");","typeGuard":null,"tryCatchPattern":"try { invoice.AddLineItem(item); } catch (InvalidOperationException ex) { // offer 'create revised invoice' flow }","preventionTips":["Edit line items only while Draft","Design duplicate-event handlers to be idempotent","Clone a new draft instead of mutating issued invoices"],"tags":["domain","state-machine","billing","invoice"],"backgroundTag":"invalid-state-transition","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}