apache/iceberg · error · IllegalArgumentException
Cannot specify both %s and %s
Error message
Cannot specify both %s and %s
What it means
GoogleAuthManager.initialize rejects configurations that set both the GCP credentials path property and the GCP credentials JSON property, since the credential source is ambiguous. It throws IllegalArgumentException('Cannot specify both %s and %s').
Source
Thrown at gcp/src/main/java/org/apache/iceberg/gcp/auth/GoogleAuthManager.java:89
public GoogleAuthManager(String managerName) {
this.name = managerName;
}
public String name() {
return name;
}
private void initialize(Map<String, String> properties) {
if (initialized) {
return;
}
String credentialsPath = properties.get(GCP_CREDENTIALS_PATH_PROPERTY);
String credentialsJson = properties.get(GCP_CREDENTIALS_JSON_PROPERTY);
boolean useCredentialsPath = credentialsPath != null && !credentialsPath.isEmpty();
boolean useCredentialsJson = credentialsJson != null && !credentialsJson.isEmpty();
if (useCredentialsPath && useCredentialsJson) {
throw new IllegalArgumentException(
String.format(
"Cannot specify both %s and %s",
GCP_CREDENTIALS_PATH_PROPERTY, GCP_CREDENTIALS_JSON_PROPERTY));
}
String scopesString = properties.getOrDefault(GCP_SCOPES_PROPERTY, DEFAULT_SCOPES);
List<String> scopes =
Strings.isNullOrEmpty(scopesString)
? ImmutableList.of()
: ImmutableList.copyOf(SPLITTER.splitToList(scopesString));
try {
if (useCredentialsPath) {
LOG.info("Using Google credentials from path: {}", credentialsPath);
try (FileInputStream credentialsStream = new FileInputStream(credentialsPath)) {
this.credentials = GoogleCredentials.fromStream(credentialsStream).createScoped(scopes);
}
} else if (useCredentialsJson) {View on GitHub (pinned to 86d9c8fc54)
Solutions
- Remove one of the two properties — keep either the credentials file path or the inline JSON
- Audit all config layers (catalog properties, Hadoop conf, env) for duplicate GCP auth settings
- Standardize on inline JSON for portability or path for secret-file deployments
Example fix
// before
props.put("gcp.credentials-path", "/path/sa.json");
props.put("gcp.credentials-json", "{...}");
// after
props.put("gcp.credentials-json", "{...}"); // single source only Defensive patterns
Strategy: validation
Validate before calling
String p = props.get("gcp.credentials-path"); String j = props.get("gcp.credentials-json");
if (p != null && !p.isEmpty() && j != null && !j.isEmpty()) { throw new IllegalArgumentException("Set only one of credentials-path / credentials-json"); } Prevention
- Keep exactly one credential source in config
- Audit merged config layers for duplicate GCP auth keys
- Document the precedence rule in your deployment config
When it happens
Trigger: Catalog/session properties contain both gcp credentials-path and gcp credentials-json (or their configured property names) with non-empty values.
Common situations: Merging config from multiple sources (catalog properties + Hadoop conf + environment) where one source sets a path and another sets inline JSON, or copy-pasting a full example config.
Related errors
- Failed to get application default credentials
- Failed to create impersonated credentials for ${impersonateS
- Table property %s must have integer value
- Failed to load Google credentials
- Failed to obtain Google access token. Cannot authenticate re
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/42dc87ec2a401024.
Report an issue: GitHub.