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
- Set iceberg.rest.auth.credential=<client_id>:<client_secret> in the catalog properties
- Or set iceberg.rest.auth.token=<bearer-token>
- Remove the auth-server-uri-only configuration and supply the credential/token the REST server actually accepts
- 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
- Always pair auth type OAUTH2 with credential or token in catalog properties
- Verify secret-injection pipelines actually populate the property at runtime
- Remember server-uri alone no longer suffices; the token endpoint is deprecated in Iceberg 2.0
- Smoke-test catalog creation in CI with the same property set used in production
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
- ICEBERG_COMMIT_ERROR
- iceberg.target-max-file-size must be at least 1 byte
- NOT_SUPPORTED
- INVALID_SESSION_PROPERTY
- /userinfo response missing principal field %s
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/ec885a1ac37d55ba.
Report an issue: GitHub.