fullstackhero/dotnet-starter-kit · error · NotFoundException

file not found

Error message

file not found

What it means

NotFoundException('file not found') thrown by RestoreFileCommandHandler when no FileAsset row with cmd.FileAssetId exists — the query uses IgnoreQueryFilters() so even soft-deleted rows would be found; only a truly absent (or wrong-tenant-filtered) id yields null. Restore is a soft-delete reversal, and a missing target is surfaced as a 404.

Solutions

  1. Verify the FileAssetId exists (list/get the file first) and belongs to the current tenant before restoring.
  2. Fix the client to use the id returned by the files API rather than one captured from another context/environment.
  3. If the file was hard-deleted, it cannot be restored — re-upload the file instead.
  4. Ensure restore requests are always made within the tenant that owns the file.

Example fix

// before
await restoreFile({ fileAssetId: staleIdFromOtherEnv }); // 404 file not found
// after
const file = await getFileAsset(fileAssetId); // confirms existence in this tenant
if (file?.isDeleted) await restoreFile({ fileAssetId: file.id });
Defensive patterns

Strategy: try-catch

Validate before calling

const file = await getFileAsset(fileAssetId); // 404 here means nothing to restore
if (!file?.isDeleted) return; // idempotent — nothing to do

Type guard

function isRestorable(f) { return f != null && f.isDeleted === true; }

Try / catch

try { await restoreFile({ fileAssetId }); } catch (e) { if (e.status === 404) { refreshList(); showToast("File no longer exists"); } else throw e; }

Prevention

When it happens

Trigger: Calling restore with a file id that was never created, an id from another tenant (tenant query filter still applies), a truncated/mistyped GUID, or referencing a file permanently deleted (hard delete) so the row no longer exists at all.

Common situations: Client restoring from a stale list after the record was purged; copying ids across environments; cross-tenant id confusion in multi-tenant testing; users hitting restore twice after a hard-delete cleanup job removed the row.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/7b73e921c710487e. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Files/Modules.Files/Features/v1/RestoreFile/RestoreFileCommandHandler.cs:21

using FSH.Modules.Files.Data;
using Mediator;
using Microsoft.EntityFrameworkCore;

namespace FSH.Modules.Files.Features.v1.RestoreFile;

public sealed class RestoreFileCommandHandler(FilesDbContext db)
    : ICommandHandler<RestoreFileCommand, Unit>
{
    public async ValueTask<Unit> Handle(RestoreFileCommand cmd, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(cmd);

        // IgnoreQueryFilters because the SoftDelete filter would otherwise hide the row.
        var f = await db.FileAssets
            .IgnoreQueryFilters()
            .FirstOrDefaultAsync(x => x.Id == cmd.FileAssetId, cancellationToken)
            .ConfigureAwait(false)
            ?? throw new NotFoundException("file not found");

        if (!f.IsDeleted)
        {
            return Unit.Value; // idempotent — already live
        }

        f.Restore();
        await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
        return Unit.Value;
    }
}

View on GitHub (pinned to 3f2959e683)