bitwarden/server · error · BadRequestException

ReportId is required.

Error message

ReportId is required.

What it means

Thrown by EnsureValidIds when reportId is provided and equals Guid.Empty. Companion guard to error 317; runs on endpoints that accept a reportId in the path.

Source

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

        }

        var orgAbility = await _organizationAbilityCacheService.GetOrganizationAbilityAsync(organizationId);
        if (orgAbility is null || !orgAbility.UseRiskInsights)
        {
            throw new BadRequestException("Your organization's plan does not support this feature.");
        }
    }

    private static void EnsureValidIds(Guid organizationId, Guid? reportId = null)
    {
        if (organizationId == Guid.Empty)
        {
            throw new BadRequestException("OrganizationId is required.");
        }

        if (reportId.HasValue && reportId.Value == Guid.Empty)
        {
            throw new BadRequestException("ReportId is required.");
        }
    }

    private async Task<OrganizationReport> GetAuthorizedReportAsync(Guid organizationId, Guid reportId)
    {
        EnsureValidIds(organizationId, reportId);
        await AuthorizeAsync(organizationId);
        var report = await _getOrganizationReportQuery.GetOrganizationReportAsync(reportId);
        if (report.OrganizationId != organizationId) throw new BadRequestException("Invalid report ID");
        return report;
    }


    // Is being used by client on V2

    [HttpGet("{organizationId}/data/summary/{reportId}")]
    public async Task<IActionResult> GetOrganizationReportSummaryAsync(Guid organizationId, Guid reportId)
    {

View on GitHub (pinned to e93b962371)

Solutions

  1. Capture the reportId from the create-report response and pass it through.
  2. Guard client-side: throw if reportId == Guid.Empty before the call.
  3. If the id is unknown, list/get the report first to recover it.

Example fix

// before
var url = $"/reports/organizations/{orgId}/{reportId}"; // reportId may be default
// after
if (reportId == Guid.Empty) throw new ArgumentException("reportId required", nameof(reportId));
var url = $"/reports/organizations/{orgId}/{reportId}";
Defensive patterns

Strategy: validation

Validate before calling

if (reportId == Guid.Empty)
    throw new ArgumentException("reportId must be a non-empty GUID.", nameof(reportId));

Type guard

static bool IsValidReportId(Guid id) => id != Guid.Empty;

Try / catch

try { await client.GetAsync($"/reports/organizations/{orgId}/{reportId}"); }
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.BadRequest && ex.Message.Contains("ReportId"))
{ /* recover the report id by listing reports, then retry */ }

Prevention

When it happens

Trigger: Client sends an empty GUID for reportId; route template left the reportId segment as the default; client passed default(Guid) after a failed lookup.

Common situations: Client lost the report id between operations; URL builder used an uninitialized field; integration test forgot to capture the created report's id.

Related errors


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