bitwarden/server · error · BadRequestException

File received does not match expected constraints.

Error message

File received does not match expected constraints.

What it means

Thrown after the self-hosted upload stream completes when ValidateFileAsync reports the received file size is outside the accepted window: [fileData.Size − 1MB, min(fileData.Size + 1MB, 501MB)]. On failure the controller deletes the uploaded blob, deletes the report record, and evicts the reports cache before throwing — so the report is fully rolled back.

Source

Thrown at src/Api/Dirt/Controllers/OrganizationReportsController.cs:420

            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)
        {
            await _storageService.DeleteReportFilesAsync(report, fileData.Id!);
            await _organizationReportRepo.DeleteAsync(report);
            await _cache.RemoveByTagAsync(
                OrganizationReportCacheConstants.BuildCacheTagForOrganizationReports(organizationId));
            throw new BadRequestException("File received does not match expected constraints.");
        }

        fileData.Validated = true;
        fileData.Size = length;
        report.SetReportFile(fileData);
        report.RevisionDate = DateTime.UtcNow;
        await _organizationReportRepo.ReplaceAsync(report);
        await _cache.RemoveByTagAsync(
            OrganizationReportCacheConstants.BuildCacheTagForOrganizationReports(organizationId));
    }

    /// <summary>
    /// Downloads an organization report file for a self-hosted instance.
    /// Validates that the organization ID and report ID are non-empty,
    /// then authorizes the caller via <see cref="AuthorizeAsync"/>.
    /// Verifies the report exists and belongs to the specified organization.
    /// Retrieves the file metadata and streams the file from local storage.
    /// Cloud-hosted instances download files directly from Azure Blob Storage

View on GitHub (pinned to e93b962371)

Solutions

  1. Measure the exact byte length of the bytes you actually stream and set FileSize to that same value at create-report time.
  2. If the source changed, create a NEW report (new FileSize) rather than re-uploading to the existing one.
  3. Check for proxy/WAF body-size limits between client and server that could truncate the upload.

Example fix

// before: FileSize from source file, upload from compressed stream
var req = new AddOrganizationReportRequestModel { FileSize = new FileInfo(srcPath).Length };
// after: measure the exact bytes you upload
using var ms = new MemoryStream();
CompressTo(srcPath, ms);
var req = new AddOrganizationReportRequestModel { FileSize = ms.Length };
Defensive patterns

Strategy: validation

Validate before calling

// Set FileSize to the exact byte count of the stream you will upload
using var ms = new MemoryStream();
await PrepareUploadStreamAsync(source, ms);
var fileSize = ms.Length;
// pass fileSize as request.FileSize at create-report time

Try / catch

try { await client.PostAsync(uploadUrl, multipart); }
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.BadRequest && ex.Message.Contains("constraints"))
{ /* report was rolled back — recreate with correct FileSize and re-upload */ }

Prevention

When it happens

Trigger: The actual uploaded byte count differs from the FileSize declared at create-report time by more than 1 MiB in either direction; the upload was truncated (network drop, proxy limit) or padded/corrupted.

Common situations: Client computes FileSize from the source file but uploads a transformed/compressed version; network interruption truncates the multipart body but the connection appears to close cleanly; intermediary (reverse proxy, WAF) strips or adds bytes; client retries upload to the same report with a different-sized file.

Related errors


AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13). Data as JSON: /api/errors/4a9b89055ef38e5c. Report an issue: GitHub.