fullstackhero/dotnet-starter-kit · error · InvalidOperationException

File type ' ' is not allowed. Allowed

Error message

File type '{extension}' is not allowed. Allowed: {string.Join(", ", rules.AllowedExtensions)}

What it means

LocalStorageService.UploadAsync resolves the FileTypeRules for the requested FileType and validates the uploaded file's extension against rules.AllowedExtensions (case-insensitive). If the extension is missing or not whitelisted, it throws InvalidOperationException before any bytes are written. This is a deliberate security guard against uploading disallowed file types.

Solutions

  1. Upload a file whose extension is in the AllowedExtensions list for the chosen FileType.
  2. Extend rules.AllowedExtensions in FileTypeMetadata if the type is legitimately allowed.
  3. Ensure the client sends the real file name with its extension, not a blob name or GUID without extension.
  4. Validate the extension in the UI before calling the API.

Example fix

// before
await storage.UploadAsync(new UploadRequest { FileName = "photo", FileType = FileType.Image, Data = bytes });

// after
var ext = Path.GetExtension("photo.jpg"); // send real name with extension
if (!FileTypeMetadata.GetRules(FileType.Image).AllowedExtensions.Contains(ext))
    throw new ArgumentException($"Unsupported image extension: {ext}");
await storage.UploadAsync(new UploadRequest { FileName = "photo.jpg", FileType = FileType.Image, Data = bytes });
Defensive patterns

Strategy: validation

Validate before calling

var ext = Path.GetExtension(fileName);
var rules = FileTypeMetadata.GetRules(fileType);
if (string.IsNullOrWhiteSpace(ext) || !rules.AllowedExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase))
    throw new ArgumentException($"Extension '{ext}' not allowed for {fileType}.");

Type guard

bool IsAllowedExtension(string? ext, FileTypeRules rules) =>
    !string.IsNullOrWhiteSpace(ext) && rules.AllowedExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase);

Try / catch

try {
    await storage.UploadAsync(request);
} catch (InvalidOperationException ex) when (ex.Message.StartsWith("File type")) {
    return Results.BadRequest(new { error = "Unsupported file type", detail = ex.Message });
}

Prevention

When it happens

Trigger: UploadAsync called with a FileName that has no extension, an empty/whitespace extension, or an extension not in the AllowedExtensions list for that FileType (e.g. uploading a .exe as an Image).

Common situations: Users uploading files with no extension (macOS/Linux exports, dotfiles); clients renaming files; mismatch between the file type selected in the UI and the actual file; adding a new extension to the UI but not to FileTypeMetadata rules.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/BuildingBlocks/Storage/Local/LocalStorageService.cs:44

        ArgumentNullException.ThrowIfNull(environment);
        _rootPath = string.IsNullOrWhiteSpace(environment.WebRootPath)
            ? Path.Combine(environment.ContentRootPath, "wwwroot")
            : environment.WebRootPath;
        _contentTypeProvider = new FileExtensionContentTypeProvider();
    }

    public async Task<string> UploadAsync<T>(FileUploadRequest request, FileType fileType, CancellationToken cancellationToken = default)
        where T : class
    {
        ArgumentNullException.ThrowIfNull(request);

        var rules = FileTypeMetadata.GetRules(fileType);
        var extension = Path.GetExtension(request.FileName);

        if (string.IsNullOrWhiteSpace(extension) ||
            !rules.AllowedExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException($"File type '{extension}' is not allowed. Allowed: {string.Join(", ", rules.AllowedExtensions)}");
        }

        if (request.Data.Count > rules.MaxSizeInMB * 1024 * 1024)
        {
            throw new InvalidOperationException($"File exceeds max size of {rules.MaxSizeInMB} MB.");
        }

#pragma warning disable CA1308 // folder names are intentionally lower-case for URLs/paths
        var folder = FolderSanitizer().Replace(typeof(T).Name.ToLowerInvariant(), "_");
#pragma warning restore CA1308
        var safeFileName = $"{Guid.NewGuid():N}_{SanitizeFileName(request.FileName)}";
        var relativePath = Path.Combine(UploadBasePath, folder, safeFileName);
        var fullPath = Path.Combine(_rootPath, relativePath);

        Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!);

        await File.WriteAllBytesAsync(fullPath, request.Data.ToArray(), cancellationToken);

View on GitHub (pinned to 3f2959e683)