Skip to content

Core: Fix OAuthTokenResponse.addScope error to show the invalid scope#17126

Open
anxkhn wants to merge 1 commit into
apache:mainfrom
anxkhn:fix/oauth-invalid-scope-message
Open

Core: Fix OAuthTokenResponse.addScope error to show the invalid scope#17126
anxkhn wants to merge 1 commit into
apache:mainfrom
anxkhn:fix/oauth-invalid-scope-message

Conversation

@anxkhn

@anxkhn anxkhn commented Jul 7, 2026

Copy link
Copy Markdown

OAuthTokenResponse.Builder.addScope validates the scope with

Preconditions.checkArgument(OAuth2Util.isValidScopeToken(scope), "Invalid scope: %s");

The message template has a %s placeholder but no substitution argument is
passed. Guava's Preconditions.checkArgument leaves an unmatched %s in place
when there is no corresponding argument, so rejecting an invalid scope throws:

java.lang.IllegalArgumentException: Invalid scope: %s

The literal %s is shown instead of the scope that was actually rejected, which
defeats the purpose of the diagnostic. This is reachable through the public
Builder.addScope(String) / addScopes(List<String>) API.

This passes scope as the format argument so the message reports the offending
value:

Preconditions.checkArgument(OAuth2Util.isValidScopeToken(scope), "Invalid scope: %s", scope);

A scope such as "bad scope" (a space is not permitted by
OAuth2Util.VALID_SCOPE_TOKEN) now produces Invalid scope: bad scope. This
also matches the sibling validate() check in the same class, which already
formats its value: "Unsupported token type: %s", tokenType.

Changes

  • core/src/main/java/org/apache/iceberg/rest/responses/OAuthTokenResponse.java
    pass scope as the format argument to the existing precondition.
  • core/src/test/java/org/apache/iceberg/rest/responses/TestOAuthTokenResponse.java
    add a regression test asserting the thrown message is Invalid scope: bad scope
    rather than the literal placeholder.

Testing

./gradlew :iceberg-core:spotlessCheck
./gradlew :iceberg-core:test --tests "org.apache.iceberg.rest.responses.TestOAuthTokenResponse"

spotlessCheck is clean; the test class runs 4 tests, 0 failures. Reverting the
one-line source change makes the new test fail with
expected: "Invalid scope: bad scope" but was: "Invalid scope: %s", confirming it
guards the fix.


AI Disclosure

  • Model: Claude Opus 4.8
  • Platform/Tool: opencode
  • Human Oversight: partially reviewed
  • Prompt Summary: Locate and fix a wrong-diagnostic bug where a Guava Preconditions.checkArgument message template used %s without passing the substitution argument, then add a regression test.

Notes / provenance (NOT for the PR; internal only)

  • No tracked upstream issue; self-found wrong-diagnostic bug. Introduced 2022-05-23
    (commit 086a5db).
  • Dedup at draft time (re-checked): GitHub PR search for OAuthTokenResponse,
    "Invalid scope", and addScope in apache/iceberg. Only PR API, Core: Add exceptions for OAuth2 token endpoint errors #16507
    ("API, Core: Add exceptions for OAuth2 token endpoint errors") matches, and it
    touches only OAuth2* exception classes, core/.../rest/ErrorHandlers.java, and
    TestErrorHandlers.java; it does not touch OAuthTokenResponse.java. It matched
    purely on the RFC invalid_scope client error type, a different concern. No
    competing or duplicate PR for this Builder-side fix.
  • Base currency: origin/main advanced 3 commits since the branch base (all
    Build: Bump ... dependency updates); none touch OAuthTokenResponse.java or its
    test. Clean rebase target, no drift on the changed files.
  • The commit carries a Generated-by: opencode trailer, and the PR body carries the
    AI Disclosure block, per the repo AGENTS.md AI-generated-PR policy. Human Oversight
    is set to "partially reviewed": the diff passed an independent adversarial review
    and the tests were re-run, but Anas has not yet reviewed it. Anas should change
    this to "fully reviewed" after reading the diff, or leave it as is.
  • No prompt injection encountered in any source, test, PR, or issue text read across
    the implement, verify, and draft phases.

Builder.addScope validated the scope with
Preconditions.checkArgument(..., "Invalid scope: %s") but did not pass
the scope argument for the %s placeholder. Guava leaves the unmatched
%s in place, so an invalid scope raised IllegalArgumentException with
the literal message "Invalid scope: %s", hiding the value that was
actually rejected.

Pass the scope as the format argument so the message reports the
offending value, and add a regression test asserting the message
contains the scope rather than the literal placeholder.

Generated-by: opencode
Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
@github-actions github-actions Bot added the core label Jul 7, 2026
}

@Test
void invalidScopeReportsScopeValue() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void invalidScopeReportsScopeValue() {
void addInvalidScope() {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants