{"record":{"id":"8abe8e4c58a225ac","repo":"bitwarden/server","slug":"resources-must-be-read-true","errorCode":null,"errorMessage":"Resources must be Read = true","messagePattern":"Resources must be Read = true","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Api/SecretsManager/Utilities/AccessPolicyHelpers.cs","lineNumber":41,"sourceCode":"                    ap.GrantedProjectId),\n                ServiceAccountSecretAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.ServiceAccountId,\n                    ap.GrantedSecretId),\n                _ => throw new ArgumentException(\"Unsupported access policy type provided.\", nameof(baseAccessPolicy)),\n            };\n        }).ToList();\n\n        if (accessPolicies.Count != distinctAccessPolicies.Count)\n        {\n            throw new BadRequestException(\"Resources must be unique\");\n        }\n    }\n\n    public static void CheckAccessPoliciesHaveReadPermission(IEnumerable<BaseAccessPolicy> accessPolicies)\n    {\n        var accessPoliciesPermission = accessPolicies.All(policy => policy.Read);\n        if (!accessPoliciesPermission)\n        {\n            throw new BadRequestException(\"Resources must be Read = true\");\n        }\n    }\n}\n","sourceCodeStart":23,"sourceCodeEnd":45,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/SecretsManager/Utilities/AccessPolicyHelpers.cs#L23-L45","documentation":"Thrown by AccessPolicyHelpers.CheckAccessPoliciesHaveReadPermission when at least one access policy in the collection has Read=false. This helper is called when creating project people access policies (ToProjectPeopleAccessPolicies). Every policy must grant at least read permission; write-only or no-access entries are rejected.","triggerScenarios":"A project people access policies request includes a user or group access policy with Read=false (and possibly Write=true), which is logically invalid — you cannot grant write without read.","commonSituations":"A client sends a policy with read=false, write=true by mistake; importing a policy set where some entries were intended for removal (read=false) rather than grant.","solutions":["Ensure every access policy in the request has Read=true.","If the intent is to revoke access, remove the policy entry entirely rather than setting Read=false.","Validate all policy entries have Read=true before submission."],"exampleFix":"// before: write-only, no read\n{\n  \"userAccessPolicyRequests\": [{\n    \"organizationUserId\": \"...\",\n    \"read\": false,\n    \"write\": true\n  }]\n}\n// after: read required\n{\n  \"userAccessPolicyRequests\": [{\n    \"organizationUserId\": \"...\",\n    \"read\": true,\n    \"write\": true\n  }]\n}","handlingStrategy":"validation","validationCode":"// Ensure all policies have Read=true before submission\nif (!policies.All(p => p.Read))\n{\n    return BadRequest(\"All access policies must have Read=true.\");\n}\nawait client.SetProjectPeoplePoliciesAsync(projectId, request);","typeGuard":"static bool AllPoliciesHaveRead(IEnumerable<BaseAccessPolicy> policies)\n    => policies.All(p => p.Read);","tryCatchPattern":"try { await client.SetPoliciesAsync(id, req); }\ncatch (ApiException ex) when (ex.Message.Contains(\"Read = true\"))\n{\n    req.Policies.ForEach(p => p.Read = true);\n    await client.SetPoliciesAsync(id, req);\n}","preventionTips":["Default all access policy forms to Read=true.","To revoke access, remove the policy entry instead of setting Read=false.","Validate Read=true on every policy client-side before submit."],"tags":["secrets-manager","access-policies","validation","bitwarden"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}