apache/iceberg · error · BadRequestException

Malformed request

Error message

Malformed request: %s: %s

What it means

The OAuth2 error handler maps OAuth token endpoint errors of types invalid_request, invalid_grant, unauthorized_client, unsupported_grant_type, and invalid_scope to BadRequestException. The token request itself was malformed or used unsupported/granted-disallowed parameters per RFC 6749.

Solutions

  1. Check the server description in the message; it names the offending parameter
  2. Remove or correct the 'scope' catalog property if the requested scope isn't supported
  3. Verify your OAuth2 server supports the grant type being used (client_credentials)
  4. Ensure you're hitting a spec-compliant token endpoint at oauth2-server-uri

Example fix

// before
props.put("oauth2-server-uri", "https://auth.example.com/authorize"); // wrong endpoint
props.put("scope", "all_the_things");
// after
props.put("oauth2-server-uri", "https://auth.example.com/token");
// remove unsupported scope
Defensive patterns

Strategy: validation

Validate before calling

String scope = props.get("scope");
if (scope != null && !supportedScopes.contains(scope)) {
  throw new IllegalArgumentException("Unsupported OAuth2 scope: " + scope);
}

Try / catch

try {
  String token = OAuth2Util.fetchToken(client, authConfig);
} catch (BadRequestException e) {
  throw new IllegalStateException("Token request rejected: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Token exchange returned HTTP 400 with one of the five handled OAuth error types — e.g. requesting an unsupported grant type (client_credentials not enabled), requesting scopes the client is not authorized for, or a malformed token request.

Common situations: Requesting 'scope' values the auth server doesn't recognize, auth server not supporting client_credentials grant, misplaced Audience/Resource parameters sent as scope, or an incompatible OAuth2 server implementation.

Understand the failure class

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/1d30a70a7421a75a. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/rest/ErrorHandlers.java:386

      } catch (Exception x) {
        LOG.warn("Unable to parse error response", x);
      }
      return ErrorResponse.builder().responseCode(code).withMessage(json).build();
    }

    @Override
    public void accept(ErrorResponse error) {
      if (error.type() != null) {
        switch (error.type()) {
          case OAuth2Properties.INVALID_CLIENT_ERROR:
            throw new NotAuthorizedException(
                "Not authorized: %s: %s", error.type(), error.message());
          case OAuth2Properties.INVALID_REQUEST_ERROR:
          case OAuth2Properties.INVALID_GRANT_ERROR:
          case OAuth2Properties.UNAUTHORIZED_CLIENT_ERROR:
          case OAuth2Properties.UNSUPPORTED_GRANT_TYPE_ERROR:
          case OAuth2Properties.INVALID_SCOPE_ERROR:
            throw new BadRequestException(
                "Malformed request: %s: %s", error.type(), error.message());
        }
      }
      throw createRESTException(error);
    }
  }
}

View on GitHub (pinned to 86d9c8fc54)