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

  1. Remove one of the two properties — keep either the credentials file path or the inline JSON
  2. Audit all config layers (catalog properties, Hadoop conf, env) for duplicate GCP auth settings
  3. 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

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


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