bitwarden/server · error · BadRequestException
ReportFileId query parameter is required
Error message
ReportFileId query parameter is required
What it means
Thrown by the self-hosted file upload endpoint when the reportFileId query parameter is missing or empty. The controller needs to know which report-file entry to attach the uploaded bytes to; without it the upload is rejected before streaming begins.
Source
Thrown at src/Api/Dirt/Controllers/OrganizationReportsController.cs:396
/// <param name="reportId">The unique identifier of the report to attach the file to.</param>
/// <param name="reportFileId">The identifier of the report file entry to upload against.</param>
[RequireFeature(FeatureFlagKeys.AccessIntelligenceNewArchitecture)]
[HttpPost("{organizationId}/{reportId}/file")]
[SelfHosted(SelfHostedOnly = true)]
[RequestSizeLimit(Constants.FileSize501mb)]
[DisableFormValueModelBinding]
public async Task UploadReportFileAsync(Guid organizationId, Guid reportId, [FromQuery] string reportFileId)
{
var report = await GetAuthorizedReportAsync(organizationId, reportId);
if (!Request?.ContentType?.Contains("multipart/") ?? true)
{
throw new BadRequestException("Invalid content.");
}
if (string.IsNullOrEmpty(reportFileId))
{
throw new BadRequestException("ReportFileId query parameter is required");
}
var fileData = report.GetReportFile();
if (fileData == null || fileData.Id != reportFileId || fileData.Validated)
{
throw new NotFoundException();
}
await Request.GetFileAsync(async (stream) =>
{
await _storageService.UploadReportDataAsync(report, fileData, stream);
});
var leeway = 1024L * 1024L; // 1 MB
var minimum = Math.Max(0, fileData.Size - leeway);
var maximum = Math.Min(fileData.Size + leeway, Constants.FileSize501mb);
var (valid, length) = await _storageService.ValidateFileAsync(report, fileData, minimum, maximum);
if (!valid)View on GitHub (pinned to e93b962371)
Solutions
- Append ?reportFileId=<id> (from the create-report response) to the upload URL.
- If lost, GET the report to recover the file entry id before uploading.
- Validate the query string is non-empty before issuing the POST.
Example fix
// before
var url = $"/reports/organizations/{orgId}/{reportId}/file";
// after
var url = $"/reports/organizations/{orgId}/{reportId}/file?reportFileId={Uri.EscapeDataString(reportFileId)}"; Defensive patterns
Strategy: validation
Validate before calling
if (string.IsNullOrWhiteSpace(reportFileId))
throw new ArgumentException("reportFileId query parameter is required for upload.", nameof(reportFileId)); Try / catch
try { await client.PostAsync($".../file?reportFileId={reportFileId}", multipart); }
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.BadRequest && ex.Message.Contains("ReportFileId"))
{ /* recover id from GET report and retry */ } Prevention
- Append reportFileId to the upload URL from the create response.
- Recover a lost id via GET report before retrying.
- Validate the query param is non-empty client-side.
When it happens
Trigger: POST to /reports/organizations/{orgId}/{reportId}/file without ?reportFileId=...; the query param is present but empty.
Common situations: Client hardcodes the upload URL template without the query param; reportFileId lost between create and upload; URL-encoding bug drops the value.
Related errors
- ReportFileId is required.
- Max file size is 500 MB.
- Resource not found.
- Invalid content.
- File received does not match expected constraints.
AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13).
Data as JSON: /api/errors/20261412f928b6dc.
Report an issue: GitHub.