prestodb/presto · error · IllegalStateException

iceberg.rest.auth.oauth2 requires either a credential or a t

Error message

iceberg.rest.auth.oauth2 requires either a credential or a token

What it means

IcebergRestCatalogFactory.builds catalog properties for the OAuth2 authentication type. The Iceberg REST spec's oauth2/tokens endpoint is deprecated, so the connector requires credentials (client id/secret) or a bearer token to be supplied up front. If the OAUTH2 auth type is selected but catalogConfig.credentialOrTokenExists() is false, the factory fails fast with IllegalStateException.

Source

Thrown at presto-iceberg/src/main/java/com/facebook/presto/iceberg/rest/IcebergRestCatalogFactory.java:157

                () -> new IllegalStateException("iceberg.rest.uri must be set for REST catalog")));

        if (catalogConfig.isTlsEnabled()) {
            properties.put(TLS_CONFIGURER_IMPL, PrestoRestTLSConfigurer.class.getName());
            catalogConfig.getKeystorePath().ifPresent(path -> properties.put(KEYSTORE_PATH, path));
            catalogConfig.getKeystorePassword().ifPresent(password -> properties.put(KEYSTORE_PASSWORD, password));
            catalogConfig.getTruststorePath().ifPresent(path -> properties.put(TRUSTSTORE_PATH, path));
            catalogConfig.getTruststorePassword().ifPresent(password -> properties.put(TRUSTSTORE_PASSWORD, password));
        }

        catalogConfig.getAuthenticationType().ifPresent(type -> {
            if (type == OAUTH2) {
                // The oauth2/tokens endpoint of the REST catalog spec has been deprecated and will
                // be removed in Iceberg 2.0 (https://github.com/apache/iceberg/pull/10603)
                // TODO auth server URI will eventually need to be made a required property
                catalogConfig.getAuthenticationServerUri().ifPresent(authServerUri -> properties.put(OAUTH2_SERVER_URI, authServerUri));

                if (!catalogConfig.credentialOrTokenExists()) {
                    throw new IllegalStateException("iceberg.rest.auth.oauth2 requires either a credential or a token");
                }
                catalogConfig.getCredential().ifPresent(credential -> properties.put(CREDENTIAL, credential));
                catalogConfig.getToken().ifPresent(token -> properties.put(TOKEN, token));
                catalogConfig.getScope().ifPresent(scope -> properties.put(SCOPE, scope));
            }
            if (type == BASIC) {
                String basicAuthUsername = catalogConfig.getBasicAuthUsername().orElseThrow(
                        () -> new IllegalStateException("iceberg.rest.auth.basic.username must be set for REST catalog when BASIC authentication is enabled"));
                String basicAuthPassword = catalogConfig.getBasicAuthPassword().orElseThrow(
                        () -> new IllegalStateException("iceberg.rest.auth.basic.password must be set for REST catalog when BASIC authentication is enabled"));
                properties.put(AUTH_TYPE, AUTH_TYPE_BASIC);
                properties.put(BASIC_USERNAME, basicAuthUsername);
                properties.put(BASIC_PASSWORD, basicAuthPassword);
            }
        });

        if (catalogConfig.isProxyEnabled()) {
            properties.put(REST_PROXY_HOSTNAME, catalogConfig.getProxyHostname().get());

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Set iceberg.rest.auth.credential=<client_id>:<client_secret> in the catalog properties
  2. Or set iceberg.rest.auth.token=<bearer-token>
  3. Remove the auth-server-uri-only configuration and supply the credential/token the REST server actually accepts
  4. Check that secret injection (env vars, keystore, config service) is populating the property at deploy time

Example fix

// before
iceberg.rest.auth.type=OAUTH2
iceberg.rest.auth.oauth2.server-uri=https://auth.example.com/token
// after
iceberg.rest.auth.type=OAUTH2
iceberg.rest.auth.credential=client123:secret456
Defensive patterns

Strategy: validation

Validate before calling

// at deploy/config time, before creating the REST catalog
if (authType == OAUTH2 && credential == null && token == null) {
    throw new IllegalStateException("Set iceberg.rest.auth.credential or iceberg.rest.auth.token");
}

Type guard

boolean hasOauth2Secret(Map<String, String> props) {
    return props.containsKey("iceberg.rest.auth.credential")
        || props.containsKey("iceberg.rest.auth.token");
}

Try / catch

try {
    IcebergRestCatalogFactory.create(properties);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("requires either a credential or a token")) {
        // load credential/token from secret store and retry config
    }
}

Prevention

When it happens

Trigger: Configuring an Iceberg REST catalog with iceberg.rest.auth.type=OAUTH2 (or oauth2 defaults applying) while providing neither a credential nor a token in the catalog properties.

Common situations: Setting iceberg.rest.auth.oauth2.server-uri (the deprecated auth-server flow) but forgetting iceberg.rest.auth.credential or token; migrating from an older connector version that could fetch tokens from the server URI; partially filled catalog config files; secrets injected by deployment tooling not reaching the properties map.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/ec885a1ac37d55ba. Report an issue: GitHub.