apache/beam · error · IllegalArgumentException

Unexpected expansion service address. Expected to be in the

Error message

Unexpected expansion service address. Expected to be in the format "<host>:<port>"

What it means

When an expansion service address is given, PythonExternalTransform.expand parses it as "<host>:<port>" so it can wait for the service port before expansion. The library throws IllegalArgumentException if the address has no colon or the colon is the first character, meaning it cannot extract a valid host/port pair.

Source

Thrown at sdks/java/extensions/python/src/main/java/org/apache/beam/sdk/extensions/python/PythonExternalTransform.java:474

  private boolean isDockerAvailable() {
    String executable = "docker";
    try {
      new ProcessBuilder(executable, "--version").start().waitFor();
      return true;
    } catch (IOException | InterruptedException exn) {
      // Ignore.
    }
    return false;
  }

  @Override
  public OutputT expand(InputT input) {
    try {
      ExternalTransforms.ExternalConfigurationPayload payload = generatePayload();
      if (!Strings.isNullOrEmpty(expansionService)) {
        int portIndex = expansionService.lastIndexOf(':');
        if (portIndex <= 0) {
          throw new IllegalArgumentException(
              "Unexpected expansion service address. Expected to be in the "
                  + "format \"<host>:<port>\"");
        }
        PythonService.waitForPort(
            expansionService.substring(0, portIndex),
            Integer.parseInt(expansionService.substring(portIndex + 1, expansionService.length())),
            15000);
        return apply(input, expansionService, payload);
      } else {
        OutputT output = null;
        int port = PythonService.findAvailablePort();
        PipelineOptionsFactory.register(PythonExternalTransformOptions.class);
        PythonExternalTransformOptions options =
            input.getPipeline().getOptions().as(PythonExternalTransformOptions.class);
        boolean useTransformService = options.getUseTransformService();
        @Nullable String customBeamRequirement = options.getCustomBeamRequirement();
        boolean pythonAvailable = isPythonAvailable();
        boolean dockerAvailable = isDockerAvailable();

View on GitHub (pinned to 12126d8942)

Solutions

  1. Pass the full address including port, e.g. "localhost:5000"
  2. If relying on the default expansion service, do not set expansionService at all (pass null/empty) so the address check is skipped
  3. Validate the address format with a regex before calling withExpansionService

Example fix

// before
transform.withExpansionService("localhost"); // throws
// after
transform.withExpansionService("localhost:5000");
Defensive patterns

Strategy: validation

Validate before calling

if (expansionService != null && !expansionService.isEmpty()) {
  int i = expansionService.lastIndexOf(':');
  if (i <= 0) throw new IllegalArgumentException("expansionService must be <host>:<port>");
  Integer.parseInt(expansionService.substring(i + 1));
}
transform.withExpansionService(expansionService);

Type guard

boolean isValidServiceAddr(String s) {
  if (s == null || s.isEmpty()) return true; // default service
  int i = s.lastIndexOf(':');
  return i > 0 && i < s.length() - 1;
}

Try / catch

try {
  transform.withExpansionService(addr);
} catch (IllegalArgumentException e) {
  // fall back to default expansion service or fix address
}

Prevention

When it happens

Trigger: Setting expansionService via withExpansionService or the constructor to a value like "localhost" (no port), ":5000" (empty host, portIndex == 0), or any string whose lastIndexOf(':') is <= 0.

Common situations: Copy-pasting a service URL without the port; using a URI like "sc://host" scheme syntax; forgetting the default port; typos in the address.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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