apache/beam · error · IllegalArgumentException

Unexpected StateSpec

Error message

Unexpected StateSpec {}

What it means

convertToBagSpecInternal converts a combining StateSpec into an equivalent bag StateSpec. It only recognizes the concrete internal spec types Beam itself creates (CombiningStateSpec / CombiningWithContextStateSpec); any other StateSpec implementation reaches the else branch and throws IllegalArgumentException. This is an internal-use invariant check protecting the conversion API.

Solutions

  1. Only create state specs via the StateSpecs factory methods; never pass custom StateSpec implementations.
  2. If a custom spec is legitimately needed, extend the conversion to handle it (upstream change) or subclass one of the recognized spec classes.
  3. Update/align the Beam SDK and runner versions so their internal StateSpec classes match.

Example fix

// before
StateSpec<Object> custom = new MyCustomSpec<>();

// after
StateSpec<CombiningState<...>> spec = StateSpecs.combining(coder, combineFn);
Defensive patterns

Strategy: validation

Validate before calling

// Verify the spec is one of Beam's own factory-produced specs before conversion
if (!(spec instanceof StateSpecs.CombiningStateSpec
    || spec instanceof StateSpecs.CombiningWithContextStateSpec)) {
  throw new IllegalArgumentException("spec must come from StateSpecs.combining(...)");
}

Try / catch

try {
  bagSpec = convertToBagSpecInternal(spec);
} catch (IllegalArgumentException e) {
  // use the original spec instead of converting
}

Prevention

When it happens

Trigger: Passing a custom or foreign StateSpec implementation (not one of the specs produced by StateSpecs factory methods) into the bag-spec conversion path used internally when a CombiningState needs to be represented as a bag, e.g. during pipeline translation for partially-consumed combining state.

Common situations: Custom StateSpec subclasses or specs from third-party extensions flowing into internal conversion; version skew where a runner/plugin passes a spec class unknown to this code; misuse of internal-use-only APIs.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/state/StateSpecs.java:357

   * <p>Convert a combining state spec to a bag of accumulators.
   */
  @Internal
  public static <InputT, AccumT, OutputT> StateSpec<BagState<AccumT>> convertToBagSpecInternal(
      StateSpec<CombiningState<InputT, AccumT, OutputT>> combiningSpec) {
    if (combiningSpec instanceof CombiningStateSpec) {
      // Checked above; conversion to a bag spec depends on the provided spec being one of those
      // created via the factory methods in this class.
      @SuppressWarnings("unchecked")
      CombiningStateSpec<InputT, AccumT, OutputT> typedSpec =
          (CombiningStateSpec<InputT, AccumT, OutputT>) combiningSpec;
      return typedSpec.asBagSpec();
    } else if (combiningSpec instanceof CombiningWithContextStateSpec) {
      @SuppressWarnings("unchecked")
      CombiningWithContextStateSpec<InputT, AccumT, OutputT> typedSpec =
          (CombiningWithContextStateSpec<InputT, AccumT, OutputT>) combiningSpec;
      return typedSpec.asBagSpec();
    } else {
      throw new IllegalArgumentException("Unexpected StateSpec " + combiningSpec);
    }
  }

  /**
   * <b><i>For internal use only; no backwards-compatibility guarantees.</i></b>
   *
   * <p>Convert a set state spec to a map-state spec.
   */
  @Internal
  public static <KeyT> StateSpec<MapState<KeyT, Boolean>> convertToMapSpecInternal(
      StateSpec<SetState<KeyT>> setStateSpec) {
    if (setStateSpec instanceof SetStateSpec) {
      // Checked above; conversion to a map spec depends on the provided spec being one of those
      // created via the factory methods in this class.
      @SuppressWarnings("unchecked")
      SetStateSpec<KeyT> typedSpec = (SetStateSpec<KeyT>) setStateSpec;
      return typedSpec.asMapSpec();
    } else {

View on GitHub (pinned to 12126d8942)