bitwarden/server · error · NotFoundException
Resource not found.
Error message
Resource not found.
What it means
Thrown by POST /{requestId} (UpdateAuthRequest) on OrganizationAuthRequestsController when GetManyAdminApprovalRequestsByManyIdsAsync returns no matching admin-approval request, or the returned request's OrganizationId != route orgId. Note this fires after ValidateAdminRequest, so the caller already passed the ManageResetPassword gate; the 404 is specifically that the org-recovery/key-connector auth request does not exist or is not pending admin approval.
Source
Thrown at src/Api/AdminConsole/Controllers/OrganizationAuthRequestsController.cs:56
var authRequests = await _authRequestRepository.GetManyPendingByOrganizationIdAsync(orgId);
var responses = authRequests
.Select(a => new PendingOrganizationAuthRequestResponseModel(a))
.ToList();
return new ListResponseModel<PendingOrganizationAuthRequestResponseModel>(responses);
}
[HttpPost("{requestId}")]
public async Task UpdateAuthRequest(Guid orgId, Guid requestId, [FromBody] AdminAuthRequestUpdateRequestModel model)
{
await ValidateAdminRequest(orgId);
var authRequest =
(await _authRequestRepository.GetManyAdminApprovalRequestsByManyIdsAsync(orgId, new[] { requestId })).FirstOrDefault();
if (authRequest == null || authRequest.OrganizationId != orgId)
{
throw new NotFoundException();
}
await _updateOrganizationAuthRequestCommand.UpdateAsync(authRequest.Id, authRequest.UserId, model.RequestApproved, model.EncryptedUserKey);
}
[HttpPost("deny")]
public async Task BulkDenyRequests(Guid orgId, [FromBody] BulkDenyAdminAuthRequestRequestModel model)
{
await ValidateAdminRequest(orgId);
var authRequests = await _authRequestRepository.GetManyAdminApprovalRequestsByManyIdsAsync(orgId, model.Ids);
foreach (var authRequest in authRequests)
{
await _authRequestService.UpdateAuthRequestAsync(authRequest.Id, authRequest.UserId,
new AuthRequestUpdateRequestModel { RequestApproved = false, });
}
}View on GitHub (pinned to e93b962371)
Solutions
- Re-fetch the pending admin-approval list and only act on requestIds still present.
- On 404, treat the request as already handled/expired and refresh the queue.
- Ensure the requestId was obtained from the same orgId's admin-approval query.
- Do not retry approval on a 404 — it indicates the request is gone.
Example fix
// before
await api.post(`/organizations/${orgId}/auth-requests/${requestId}`, { RequestApproved: true, ... });
// after
var pending = await api.get(`/organizations/${orgId}/auth-requests/pending`);
if (!pending.Any(r => r.Id == requestId)) { refreshQueue(); return; }
await api.post(`/organizations/${orgId}/auth-requests/${requestId}`, { RequestApproved: true, ... }); Defensive patterns
Strategy: validation
Validate before calling
// Only act on requestIds still present in the admin-approval queue
var pending = await authRequestApi.GetPendingAdminAsync(orgId);
if (!pending.Any(r => r.Id == requestId)) { refreshQueue(); return; } Type guard
static bool RequestStillPending(AuthRequestSummary r, Guid orgId)
=> r is not null && r.OrganizationId == orgId && r.IsPendingAdminApproval; Try / catch
try { await api.PostAsync($"/auth-requests/{requestId}", body); }
catch (ApiException e) when (e.StatusCode == HttpStatusCode.NotFound)
{ // already resolved/expired/gone — do not retry approval
refreshQueue(); } Prevention
- Re-fetch the pending admin-approval list before each action.
- Obtain requestId only from the same orgId's approval query.
- Treat 404 as resolved/expired and refresh, never as retriable.
When it happens
Trigger: Approving/denying an org auth request (admin-initiated reset / SSO key connector approval) whose requestId is unknown, already resolved, or belongs to a different org. Only requests returned by the admin-approval query are visible; others look 'not found'.
Common situations: Approving a request that was already approved/denied or expired; stale requestId in the admin UI; cross-org requestId; race where the user cancelled the request.
Related errors
- One or more collections not found.
- Last synced date must be in the past.
- Only service accounts can sync secrets.
- You cannot import this much data at once, the limit is 1000
- A secret can only be in one project at a time.
AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13).
Data as JSON: /api/errors/f58006ecd765e8d5.
Report an issue: GitHub.