{"record":{"id":"5172fe637ef61957","repo":"fullstackhero/dotnet-starter-kit","slug":"ticket-command-ticketid-not-found-5172fe","errorCode":null,"errorMessage":"Ticket {command.TicketId} not found.","messagePattern":"Ticket (.+?) not found\\.","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Modules/Tickets/Modules.Tickets/Features/v1/Tickets/RestoreTicket/RestoreTicketCommandHandler.cs","lineNumber":21,"sourceCode":"using FSH.Modules.Tickets.Contracts.v1.Tickets;\nusing FSH.Modules.Tickets.Data;\nusing Mediator;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace FSH.Modules.Tickets.Features.v1.Tickets.RestoreTicket;\n\npublic sealed class RestoreTicketCommandHandler(TicketsDbContext dbContext)\n    : ICommandHandler<RestoreTicketCommand, Guid>\n{\n    public async ValueTask<Guid> Handle(RestoreTicketCommand command, CancellationToken cancellationToken)\n    {\n        ArgumentNullException.ThrowIfNull(command);\n\n        var ticket = await dbContext.Tickets\n            .IgnoreQueryFilters([QueryFilters.SoftDelete])\n            .FirstOrDefaultAsync(t => t.Id == command.TicketId, cancellationToken)\n            .ConfigureAwait(false)\n            ?? throw new NotFoundException($\"Ticket {command.TicketId} not found.\");\n\n        ticket.Restore();\n        await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);\n        return ticket.Id;\n    }\n}\n","sourceCodeStart":3,"sourceCodeEnd":28,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Tickets/Modules.Tickets/Features/v1/Tickets/RestoreTicket/RestoreTicketCommandHandler.cs#L3-L28","documentation":"RestoreTicket's handler ignores the soft-delete query filter so it can see deleted tickets, but still throws NotFoundException when no row matches the TicketId at all. Soft-deleted rows ARE visible here, so this error means the ticket record is genuinely absent (or filtered out by tenant isolation), not merely deleted.","triggerScenarios":"Calling RestoreTicket with a TicketId that does not exist in the table at all; the row exists but belongs to a different tenant (tenant query filter still applies since only the SoftDelete filter is ignored); the id is malformed/another entity's id.","commonSituations":"Attempting to restore a ticket that was hard-deleted (e.g. removed by a purge/cleanup job rather than soft-deleted); restore after a database was re-seeded so old ids vanished; cross-tenant restore attempt where the tenant context is wrong; typos when copying a GUID.","solutions":["Query the table directly (including hard-deleted rows) to confirm the row physically exists before restoring.","Check the tenant context of the request matches the ticket's TenantId.","If the ticket was hard-deleted, restore from backup or recreate the ticket instead of calling RestoreTicket.","Validate the id in the client before the call (non-empty GUID format)."],"exampleFix":"// before\nawait api.RestoreTicket(new RestoreTicketCommand(id)); // throws if row is gone\n// after\ntry {\n    await api.RestoreTicket(new RestoreTicketCommand(id));\n} catch (ProblemDetailsException p) when (p.Status == 404) {\n    logger.LogWarning(\"Ticket {TicketId} no longer exists; cannot restore\", id);\n}","handlingStrategy":"validation","validationCode":"const row = await api.queryTickets({ includeDeleted: true, id });\nif (!row) throw new SkipError('Row physically absent; restore impossible');","typeGuard":null,"tryCatchPattern":"try {\n  await restoreTicket(id);\n} catch (ApiError e) when (e.Status === 404) {\n  logger.warn('Cannot restore, ticket was hard-deleted');\n}","preventionTips":["Distinguish soft-delete (restorable) from hard-delete (not restorable) in tooling.","Verify ids come from the same tenant/environment you call.","Validate GUID format client-side before submitting."],"tags":["ef-core","not-found","soft-delete","cqrs","tickets"],"backgroundTag":"entity-not-found","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"}