fullstackhero/dotnet-starter-kit · error · CustomException
A closed ticket cannot be edited — reopen it first.
Error message
A closed ticket cannot be edited — reopen it first.
What it means
Ticket.UpdateDetails refuses to edit a Closed ticket, throwing CustomException with HTTP 409 Conflict. Closed tickets are immutable in this domain; they must be reopened before title, description, or priority can change. The title argument is also validated as non-empty before this check.
Solutions
- Reopen the ticket first, then apply the update.
- Reload the ticket to refresh Status before editing.
- Handle 409 in the client and offer a 'Reopen and edit' action.
- Disable edit controls in the UI when the ticket status is Closed.
Example fix
// before
ticket.UpdateDetails(title, description, priority); // 409 if closed
// after
if (ticket.Status == TicketStatus.Closed)
{
ticket.Reopen();
}
ticket.UpdateDetails(title, description, priority); Defensive patterns
Strategy: validation
Validate before calling
if (ticket.status === TicketStatus.Closed) {
throw new Error('Reopen the ticket before editing.');
}
if (!title?.trim()) {
throw new Error('Title is required.');
}
ticket.updateDetails(title, description, priority); Type guard
bool CanEdit(Ticket t) => t.Status != TicketStatus.Closed && !string.IsNullOrWhiteSpace(t.Title);
Try / catch
try
{
ticket.UpdateDetails(title, description, priority);
}
catch (CustomException ex) when (ex.StatusCode == HttpStatusCode.Conflict)
{
ticket.Reopen();
ticket.UpdateDetails(title, description, priority);
} Prevention
- Disable the edit form when ticket status is Closed.
- Re-fetch ticket status before submitting edits from long-open forms.
- Treat 409 as 'ticket was closed meanwhile' and offer Reopen-and-edit.
- Trim and require the title client-side to fail fast before hitting the aggregate.
When it happens
Trigger: Calling UpdateDetails (or the update-ticket endpoint) on a ticket with Status == TicketStatus.Closed.
Common situations: Editing an old ticket from a stale browser tab after someone closed it; concurrent edits where close won the race; automated bulk-update jobs not checking status.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- A closed ticket cannot be resolved — reopen it first.
- Only a resolved ticket can be closed — current status is
- A closed ticket cannot accept new comments — reopen it…
- Cannot a ticket in status — reopen it first.
- Top-up request cannot be rejected because it is (only…
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/fa41a224f2ef2b69.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Tickets/Modules.Tickets/Domain/Ticket.cs:168
(IEnumerable<string>?)null,
HttpStatusCode.Conflict);
}
ClosedAtUtc = DateTime.UtcNow;
UpdatedAtUtc = DateTime.UtcNow;
TransitionStatus(TicketStatus.Closed);
}
/// <summary>
/// Edits the mutable details of an open/in-progress/resolved ticket. A closed ticket is
/// frozen — it must be reopened first.
/// </summary>
public void UpdateDetails(string title, string? description, TicketPriority priority)
{
ArgumentException.ThrowIfNullOrWhiteSpace(title);
if (Status == TicketStatus.Closed)
{
throw new CustomException(
"A closed ticket cannot be edited — reopen it first.",
(IEnumerable<string>?)null,
HttpStatusCode.Conflict);
}
Title = title.Trim();
Description = string.IsNullOrWhiteSpace(description) ? null : description.Trim();
Priority = priority;
UpdatedAtUtc = DateTime.UtcNow;
}
public void Reopen()
{
if (Status is TicketStatus.Open or TicketStatus.InProgress)
{
return;
}
View on GitHub (pinned to 3f2959e683)