dotnet/aspnetcore · error · Error

There is no file with ID ${fileId}. The file list may have c

Error message

There is no file with ID ${fileId}. The file list may have changed. See https://aka.ms/aspnet/blazor-input-file-multiple-selections.

What it means

Thrown by getFileById when the requested file ID is not present in the InputFile element's internal _blazorFilesById map. Blazor's InputFile JS interop tracks chosen files by a monotonically-increasing ID; that map is rebuilt from scratch on every 'change' event and cleared on 'cancel', so any stale file ID held by .NET becomes invalid the moment the user picks files again or cancels the dialog.

Source

Thrown at src/Components/Web.JS/src/InputFile.ts:117

    contentType: format,
    blob: resizedImageBlob ? resizedImageBlob : originalFile.blob,
  };

  elem._blazorFilesById[result.id] = result;

  return result;
}

async function readFileData(elem: InputElement, fileId: number): Promise<Blob> {
  const file = getFileById(elem, fileId);
  return file.blob;
}

export function getFileById(elem: InputElement, fileId: number): BrowserFile {
  const file = elem._blazorFilesById[fileId];

  if (!file) {
    throw new Error(`There is no file with ID ${fileId}. The file list may have changed. See https://aka.ms/aspnet/blazor-input-file-multiple-selections.`);
  }

  return file;
}

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Process files synchronously inside the OnChange handler (or kick off the stream read immediately) before the user can select again, rather than holding IBrowserFile references long-term.
  2. Copy the bytes to your own buffer/stream during OnChange and never reference the IBrowserFile afterward.
  3. If you must defer, capture only the data you need into component state in OnChange and treat subsequent OnChange as replacing the whole set.
  4. Avoid calling OpenReadStream on a file whose change event has been superseded; guard with a flag tracking whether the list changed.

Example fix

// before: hold the file, use later
private IBrowserFile _file; // set in OnChange, used in a button click
await _file.OpenReadStream().CopyToAsync(ms); // throws if user picked again

// after: read immediately in OnChange
async Task OnChange(InputFileChangeEventArgs e)
{
    await using var stream = e.File.OpenReadStream(maxAllowedSize);
    await stream.CopyToAsync(_ms); // done with IBrowserFile right away
}
Defensive patterns

Strategy: validation

Validate before calling

// Before calling IBrowserFile.OpenReadStream, ensure the file is still current.
// Track a token that changes on each InputFile OnChange:
private int _fileSetToken;
async Task OnChange(InputFileChangeEventArgs e)
{
    _fileSetToken++;
    var token = _fileSetToken;
    // capture bytes now; do not retain e.File past this handler
}
// In any deferred action, compare token == _fileSetToken before using a file.

Prevention

When it happens

Trigger: Calling IBrowserFile.OpenReadStream / ReadAsStreamAsync, or InputFile's toImageFile/readFileData JS interop, with a IBrowserFile reference obtained from a previous InputFile change callback after the user has since reopened the picker and selected new files (or pressed Cancel). Also triggered when multiple-file selection is disabled and code assumes the ID stays valid across selections.

Common situations: Storing IBrowserFile instances in component state and reusing them after another OnChange; wiring an upload button that triggers a second change before processing the first; migrating code from single-file to multiple-file selection without invalidating cached file references.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/01df505ee37907f5. Report an issue: GitHub.