{"record":{"id":"8751f5c83225023e","repo":"bitwarden/server","slug":"resource-not-found-8751f5","errorCode":null,"errorMessage":"Resource not found.","messagePattern":"Resource not found\\.","errorType":"http","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Api/SecretsManager/Controllers/SecretsTrashController.cs","lineNumber":46,"sourceCode":"        IEmptyTrashCommand emptyTrashCommand,\n        IRestoreTrashCommand restoreTrashCommand,\n        IUserService userService,\n        IEventService eventService)\n    {\n        _currentContext = currentContext;\n        _secretRepository = secretRepository;\n        _emptyTrashCommand = emptyTrashCommand;\n        _restoreTrashCommand = restoreTrashCommand;\n        _userService = userService;\n        _eventService = eventService;\n    }\n\n    [HttpGet(\"secrets/{organizationId}/trash\")]\n    public async Task<SecretWithProjectsListResponseModel> ListByOrganizationAsync(Guid organizationId)\n    {\n        if (!_currentContext.AccessSecretsManager(organizationId))\n        {\n            throw new NotFoundException();\n        }\n\n        if (!await _currentContext.OrganizationAdmin(organizationId))\n        {\n            throw new UnauthorizedAccessException();\n        }\n\n        var secrets = await _secretRepository.GetManyDetailsByOrganizationIdInTrashAsync(organizationId);\n        return new SecretWithProjectsListResponseModel(secrets);\n    }\n\n    [HttpPost(\"secrets/{organizationId}/trash/empty\")]\n    public async Task EmptyTrashAsync(Guid organizationId, [FromBody] List<Guid> ids)\n    {\n        if (!_currentContext.AccessSecretsManager(organizationId))\n        {\n            throw new NotFoundException();\n        }","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/SecretsManager/Controllers/SecretsTrashController.cs#L28-L64","documentation":"Thrown at SecretsTrashController.cs:46 inside ListByOrganizationAsync (GET secrets/{org}/trash). The first guard checks _currentContext.AccessSecretsManager(organizationId); if false the controller throws NotFoundException -> HTTP 404. The caller has no Secrets Manager access to that organization (checked before the admin check).","triggerScenarios":"GET /secrets/{orgId}/trash by a principal with no Secrets Manager access to the route organization.","commonSituations":"Standard password-manager user without an SM seat; service account from another org; SM access revoked.","solutions":["Ensure the caller has Secrets Manager access to the organization.","Assign an SM seat to the user or use a service account provisioned under that org.","Confirm the organization id is correct for this caller."],"exampleFix":"// before: token without SM access lists trash\nawait client.GetAsync($\"/secrets/{orgId}/trash\"); // 404\n\n// after: use an SM-enabled admin identity\nvar smAdminClient = ClientFor(smAdminCredential);\nawait smAdminClient.GetAsync($\"/secrets/{orgId}/trash\");","handlingStrategy":"validation","validationCode":"if (!await HasSecretsManagerAccessAsync(orgId))\n    throw new UnauthorizedAccessException(\"No SM access for org\");\nawait client.GetAsync($\"/secrets/{orgId}/trash\");","typeGuard":null,"tryCatchPattern":"try { await client.GetAsync($\"/secrets/{orgId}/trash\"); }\ncatch (ApiException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { Log.Warn(\"No SM access; use an SM-enabled identity\"); }","preventionTips":["Gate the trash UI behind an SM-access check.","Assign an SM seat or use a service account under that org.","Confirm the org id belongs to the caller."],"tags":["csharp","aspnet","bitwarden","secrets-manager","authorization","trash","api"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}