apache/beam · error · IllegalArgumentException
Experimental host can only be used with instance id: + EXPER
Error message
Experimental host can only be used with instance id: + EXPERIMENTAL_HOST_INSTANCE_ID
What it means
SpannerAccessor.buildSpannerOptions() allows an experimental Spanner host endpoint only as a special test/experiment path: when the experimentalHost option is set, the instance id must equal EXPERIMENTAL_HOST_INSTANCE_ID; otherwise it throws IllegalArgumentException. This guards the experimental feature so it cannot be accidentally combined with production instance configurations.
Source
Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerAccessor.java:271
ValueProvider<String> projectId = spannerConfig.getProjectId();
if (projectId != null) {
builder.setProjectId(projectId.get());
}
ServiceFactory<Spanner, SpannerOptions> serviceFactory = spannerConfig.getServiceFactory();
if (serviceFactory != null) {
builder.setServiceFactory(serviceFactory);
}
builder.setHost(spannerConfig.getHostValue());
ValueProvider<String> experimentalHost = spannerConfig.getExperimentalHost();
if (experimentalHost != null && !Strings.isNullOrEmpty(experimentalHost.get())) {
builder.setExperimentalHost(experimentalHost.get());
ValueProvider<Boolean> plainText = spannerConfig.getPlainText();
ValueProvider<String> instanceId = spannerConfig.getInstanceId();
if (Strings.isNullOrEmpty(instanceId.get())
|| !instanceId.get().equals(EXPERIMENTAL_HOST_INSTANCE_ID)) {
throw new IllegalArgumentException(
"Experimental host can only be used with instance id: "
+ EXPERIMENTAL_HOST_INSTANCE_ID);
}
if (plainText != null && Boolean.TRUE.equals(plainText.get())) {
builder.setChannelConfigurator(b -> b.usePlaintext());
}
ValueProvider<String> clientCert = spannerConfig.getClientCertPath();
ValueProvider<String> clientKey = spannerConfig.getClientCertKeyPath();
if (clientCert != null
&& clientKey != null
&& clientCert.isAccessible()
&& clientKey.isAccessible()
&& !Strings.isNullOrEmpty(clientCert.get())
&& !Strings.isNullOrEmpty(clientKey.get())) {
builder.useClientCert(clientCert.get(), clientKey.get());
}
}
View on GitHub (pinned to 12126d8942)
Solutions
- Remove the experimentalHost option to use the standard Spanner endpoint
- Set the instance id exactly to EXPERIMENTAL_HOST_INSTANCE_ID if you truly intend to use the experimental host
- Check pipeline options/argv for stray --experimentalHost flags
- Verify which SpannerAccessor/SpannerConfig instance is being built and its instanceId value
Example fix
// before --experimentalHost=staging.googleapis.com --spannerInstanceId=prod-instance // after --spannerInstanceId=prod-instance // experimentalHost removed
Defensive patterns
Strategy: validation
Validate before calling
if (experimentalHost != null && !experimentalHost.isEmpty()
&& !EXPERIMENTAL_HOST_INSTANCE_ID.equals(instanceId)) {
throw new IllegalArgumentException("experimentalHost requires instance id " + EXPERIMENTAL_HOST_INSTANCE_ID);
} Try / catch
try { accessor = SpannerAccessor.getOrCreate(config); } catch (IllegalArgumentException e) { /* strip experimentalHost and retry */ } Prevention
- Never set experimentalHost in production configs
- Audit pipeline option defaults for stray experimental flags
- Use separate option profiles for experimental vs production runs
When it happens
Trigger: Setting SpannerConfig.experimentalHost (e.g. via --experimentalHost or withExperimentalHost) to a non-empty value while spannerConfig.instanceId is missing or does not equal EXPERIMENTAL_HOST_INSTANCE_ID.
Common situations: Copy-pasting experimental host flags from internal docs/testing into production pipeline options; leaving an experimental host env/option set in CI; mixing standard instance configs with an experimental endpoint.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Unrecognized dialect: + dialect.name()
- Failed to parse DirectedReadOptions from string: + directedR
- MetadataInstance can't be empty
- MetadataDatabase can't be empty
- Unrecognized value for stable unique names:
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/6f4967e0071550e1.
Report an issue: GitHub.