bitwarden/server · error · NotFoundException
Resource not found.
Error message
Resource not found.
What it means
Thrown by GetMemberCipherDetails when the calling user lacks the AccessReports permission for the given orgId. Bitwarden deliberately returns 404 (NotFoundException with no message) instead of 403 to avoid leaking the existence of the organization or the endpoint to unauthorized users. The permission check _currentContext.AccessReports(orgId) returns false.
Source
Thrown at src/Api/Dirt/Controllers/ReportsController.cs:66
_getPasskeyDirectoryQuery = getPasskeyDirectoryQuery;
_logger = logger;
}
/// <summary>
/// Organization member information containing a list of cipher ids
/// assigned
/// </summary>
/// <param name="orgId">Organzation Id</param>
/// <returns>IEnumerable of MemberCipherDetailsResponseModel</returns>
/// <exception cref="NotFoundException">If Access reports permission is not assigned</exception>
[HttpGet("member-cipher-details/{orgId}")]
public async Task<IEnumerable<MemberCipherDetailsResponseModel>> GetMemberCipherDetails(Guid orgId)
{
// Using the AccessReports permission here until new permissions
// are needed for more control over reports
if (!await _currentContext.AccessReports(orgId))
{
throw new NotFoundException();
}
var riskDetails = await GetRiskInsightsReportDetails(new RiskInsightsReportRequest { OrganizationId = orgId });
var responses = riskDetails.Select(x => new MemberCipherDetailsResponseModel(x));
return responses;
}
/// <summary>
/// Access details for an organization member. Includes the member information,
/// group collection assignment, and item counts
/// </summary>
/// <param name="orgId">Organization Id</param>
/// <returns>IEnumerable of MemberAccessReportResponseModel</returns>
/// <exception cref="NotFoundException">If Access reports permission is not assigned</exception>
[HttpGet("member-access/{orgId}")]
public async Task<IEnumerable<MemberAccessDetailReportResponseModel>> GetMemberAccessReport(Guid orgId)View on GitHub (pinned to e93b962371)
Solutions
- Grant the AccessReports permission to the user's role in the organization admin panel.
- Verify the calling user is an active member of the target organization.
- If using a service account or API key, ensure it was created with reports-scoped access.
- Confirm the orgId in the URL matches an organization the user actually belongs to.
Example fix
// before
var details = await api.GetMemberCipherDetailsAsync(orgId);
// after — check access first
var perms = await api.GetMyPermissionsAsync(orgId);
if (!perms.Contains("access_reports"))
{
// surface a clear auth error instead of hitting the opaque 404
throw new UnauthorizedAccessException("AccessReports permission required.");
}
var details = await api.GetMemberCipherDetailsAsync(orgId); Defensive patterns
Strategy: validation
Validate before calling
// Check permissions before calling the report endpoint
var access = await _currentContext.AccessReports(orgId);
if (!access)
return Forbid("AccessReports permission is required.");
var details = await _reportQuery.GetMemberCipherDetailsAsync(orgId); Type guard
public static bool HasReportsAccess(CurrentContext ctx, Guid orgId) =>
ctx.Permissions.TryGetValue(orgId, out var p) && p.AccessReports; Try / catch
try
{
var details = await _reportService.GetMemberCipherDetailsAsync(orgId);
}
catch (NotFoundException)
{
// 404 may mean either no access or no data — check permissions separately
if (!await _currentContext.AccessReports(orgId))
return Forbid();
return NotFound();
} Prevention
- Verify the user's role includes AccessReports before calling report endpoints.
- Cache the user's permission set client-side and disable report UI when missing.
- Use service accounts with explicit reports-scoped access for API integrations.
When it happens
Trigger: GET /reports/member-cipher-details/{orgId} called by a user who is not an org admin/owner, or whose role does not include the AccessReports permission, or who is not a member of the organization at all.
Common situations: A custom-role user whose permissions were recently trimmed; a service account token that was provisioned without reports access; a user removed from the org but still holding a stale session; testing against the wrong orgId.
Related errors
AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13).
Data as JSON: /api/errors/d177158501afd3f4.
Report an issue: GitHub.