{"record":{"id":"9e2cd6b3eef814a9","repo":"microg/GmsCore","slug":"missing-required-properties-scopes","errorCode":null,"errorMessage":"Missing required properties: scopes","messagePattern":"Missing required properties: scopes","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/RevokeAccessRequest.java","lineNumber":59,"sourceCode":"        this.scopes = scopes;\n        this.account = account;\n        this.sessionId = sessionId;\n    }\n\n    /**\n     * Returns a new {@link RevokeAccessRequest.Builder}.\n     */\n    @NonNull\n    public static RevokeAccessRequest.Builder builder() {\n        return new Builder() {\n            private List<Scope> scopes;\n            private Account account;\n            private String sessionId;\n\n            @NonNull\n            @Override\n            public RevokeAccessRequest build() {\n                if (scopes == null) throw new IllegalStateException(\"Missing required properties: scopes\");\n                if (account == null) throw new IllegalStateException(\"Missing required properties: account\");\n                return new RevokeAccessRequest(scopes, account, sessionId);\n            }\n\n            @NonNull\n            @Override\n            public Builder setAccount(@NonNull Account account) {\n                this.account = account;\n                return this;\n            }\n\n            @NonNull\n            @Override\n            public Builder setScopes(@NonNull List<Scope> scopes) {\n                this.scopes = scopes;\n                return this;\n            }\n","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/RevokeAccessRequest.java#L41-L77","documentation":"RevokeAccessRequest.Builder.build() requires both scopes and account. When scopes is null (setScopes never called), build() throws IllegalStateException 'Missing required properties: scopes' before even checking account. This guards against sending an access-revocation request without the OAuth scopes to revoke.","triggerScenarios":"RevokeAccessRequest.builder()...build() where setScopes(...) was never invoked (or was passed conditions that skipped it).","commonSituations":"Building the request from a scopes list that was empty/null due to a failed config load; forgetting setScopes because account setup was the focus; refactors moving scope collection elsewhere.","solutions":["Call setScopes(...) with the list of scopes to revoke before build().","Derive scopes from the stored credential/token rather than external config to avoid empty values.","Guard: if scopes == null || scopes.isEmpty(), abort the revocation flow with a user-visible error instead of building."],"exampleFix":"// before\nRevokeAccessRequest req = RevokeAccessRequest.builder().setAccount(account).build();\n// after\nRevokeAccessRequest req = RevokeAccessRequest.builder()\n    .setScopes(scopes) // e.g. Collections.singletonList(OAuth2.SCOPE_PROFILE)\n    .setAccount(account)\n    .build();","handlingStrategy":"validation","validationCode":"if (scopes == null || scopes.isEmpty()) { abortRevocation(\"no scopes to revoke\"); return; }","typeGuard":null,"tryCatchPattern":"try { req = RevokeAccessRequest.builder().setScopes(scopes).setAccount(account).build(); } catch (IllegalStateException e) { log.warn(\"RevokeAccessRequest incomplete: \" + e.getMessage()); }","preventionTips":["Always chain setScopes and setAccount in one expression before build().","Load scopes from a single trusted source (constants or token's scope field).","Write a buildRevokeAccessRequest(scopes, account) helper that asserts both non-null."],"tags":["android","identity","oauth","builder","required-property"],"backgroundTag":"missing-required-argument","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}