apache/beam · error · IllegalArgumentException

Project and location must be null if API key is set

Error message

Project and location must be null if API key is set

What it means

GeminiModelHandler supports two mutually exclusive auth modes: an API key (Gemini API) or Vertex AI (project + location). createClient enforces that when an API key is set, project and location must be null; otherwise this IllegalArgumentException is thrown because the two credential modes conflict.

Solutions

  1. Remove setProject/setLocation if you authenticate with an API key.
  2. Remove setApiKey and supply both project and location if you intend to use Vertex AI.
  3. Make your config loading conditional: only populate vertex fields when apiKey is absent (and vice versa).

Example fix

// before
params.setApiKey(key); params.setProject("my-proj"); params.setLocation("us-central1");
// after (API key mode)
params.setApiKey(key);
Defensive patterns

Strategy: validation

Validate before calling

if (params.getApiKey() != null && (params.getProject() != null || params.getLocation() != null)) {
  throw new IllegalArgumentException("API key mode conflicts with Vertex AI project/location");
}

Type guard

boolean isConsistentAuth(GeminiModelParameters<?,?> p) { return p.getApiKey() == null ? (p.getProject() != null && p.getLocation() != null) : (p.getProject() == null && p.getLocation() == null); }

Try / catch

try { handler.createClient(params); } catch (IllegalArgumentException e) { throw new IllegalStateException("Gemini auth config conflict: " + e.getMessage(), e); }

Prevention

When it happens

Trigger: Building GeminiModelParameters with both setApiKey(...) and setProject(...)/setLocation(...), then calling createClient, which detects the conflicting combination.

Common situations: Copy-pasting Vertex AI config (project/location) into an API-key setup or vice versa; environment-driven config that sets all variables regardless of auth mode.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/f7002013afdb6c80. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/ml/inference/gemini/src/main/java/org/apache/beam/sdk/ml/inference/gemini/GeminiModelHandler.java:52

 */
@SuppressWarnings("nullness")
public class GeminiModelHandler<InputT extends BaseInput, OutputT extends BaseResponse>
    implements BaseModelHandler<GeminiModelParameters<InputT, OutputT>, InputT, OutputT> {

  private transient Client client;
  private GeminiModelParameters<InputT, OutputT> modelParameters;

  @Override
  public void createClient(GeminiModelParameters<InputT, OutputT> parameters) {
    if (parameters == null) {
      throw new NullPointerException("GeminiModelParameters must not be null");
    }
    this.modelParameters = parameters;

    // Configure client based on vertex or API key
    if (parameters.getApiKey() != null) {
      if (parameters.getProject() != null || parameters.getLocation() != null) {
        throw new IllegalArgumentException("Project and location must be null if API key is set");
      }
      this.client = Client.builder().apiKey(parameters.getApiKey()).build();
    } else {
      Client.Builder builder = Client.builder();
      if (parameters.getProject() != null && parameters.getLocation() != null) {
        builder.vertexAI(true).project(parameters.getProject()).location(parameters.getLocation());
      } else if (parameters.getProject() != null || parameters.getLocation() != null) {
        throw new IllegalArgumentException(
            "Project and location must both be provided if one is provided");
      }
      this.client = builder.build();
    }
  }

  @Override
  public Iterable<PredictionResult<InputT, OutputT>> request(List<InputT> input) {
    try {
      GeminiRequestFunction<InputT, OutputT> requestFn = modelParameters.getRequestFn();

View on GitHub (pinned to 12126d8942)