apache/beam · error · IllegalArgumentException

Output coders were already specified

Error message

Output coders were already specified

What it means

withOutputCoders sets the map of output PCollection coders for the cross-language transform. The library throws IllegalArgumentException if output coders were already specified on this builder, since redefining the coder map would silently discard previously configured coders. Coders can only be set once per transform instance.

Source

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

    if (typeHints.containsKey(argType)) {
      throw new IllegalArgumentException(
          String.format("typehint for arg type %s already exists", argType));
    }
    typeHints.put(argType, fieldType);
    return this;
  }

  /**
   * Specifies the keys and {@link Coder}s of the output {@link PCollection}s produced by this
   * transform.
   *
   * @param outputCoders a mapping from output keys to {@link Coder}s.
   * @return updated wrapper for the cross-language transform.
   */
  public PythonExternalTransform<InputT, OutputT> withOutputCoders(
      Map<String, Coder<?>> outputCoders) {
    if (this.outputCoders.size() > 0) {
      throw new IllegalArgumentException("Output coders were already specified");
    }
    this.outputCoders.putAll(outputCoders);
    return this;
  }

  /**
   * Specifies the {@link Coder} of the output {@link PCollection}s produced by this transform.
   * Should only be used if this transform produces a single output.
   *
   * @param outputCoder output {@link Coder} of the transform.
   * @return updated wrapper for the cross-language transform.
   */
  public PythonExternalTransform<InputT, OutputT> withOutputCoder(Coder<?> outputCoder) {
    if (this.outputCoders.size() > 0) {
      throw new IllegalArgumentException("Output coders were already specified");
    }

    // Output key should not matter when only specifying a single output.

View on GitHub (pinned to 12126d8942)

Solutions

  1. Remove the duplicate coder-setting call and keep a single withOutputCoders invocation
  2. Combine all coders into one map and pass it in a single call
  3. Build a fresh PythonExternalTransform if you need a different coder configuration

Example fix

// before
ext.withOutputCoder(myCoder).withOutputCoders(coderMap); // throws
// after
ext.withOutputCoders(coderMap); // single specification
Defensive patterns

Strategy: validation

Validate before calling

if (outputCoders != null && !outputCoders.isEmpty()) {
  throw new IllegalStateException("output coders already set");
}
transform.withOutputCoders(outputCoders);

Try / catch

try {
  transform.withOutputCoders(map);
} catch (IllegalArgumentException e) {
  // coders already set; reuse existing configuration
}

Prevention

When it happens

Trigger: Calling withOutputCoders(Map) when this.outputCoders is non-empty — i.e. after a prior withOutputCoders or withOutputCoder call on the same PythonExternalTransform.

Common situations: Chaining both withOutputCoder(...) and withOutputCoders(...); calling withOutputCoders twice in a fluent chain; reusing a pre-configured transform object in two pipelines.

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


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