apache/beam · error · IllegalArgumentException

Unable to infer SQL type from type variable . This usually m

Error message

Unable to infer SQL type from type variable . This usually means you are trying to use a generic type whose type information is not known at runtime. You can wrap your CombineFn into typed subclass by 'new TypedCombineFnDelegate<...>(combineFn) {}'

What it means

Beam SQL cannot map a UDAF's input type to a SQL type when the CombineFn's generic type is a TypeVariable (unknown at runtime due to Java type erasure). Calcite needs a concrete RelDataType, and a raw generic CombineFn gives it nothing to infer from. The library throws to force you to supply a typed subclass (TypedCombineFnDelegate) that captures the type parameters in the anonymous class's superclass.

Source

Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/UdafImpl.java:75

    List<FunctionParameter> para = new ArrayList<>();
    para.add(
        new FunctionParameter() {
          @Override
          public int getOrdinal() {
            return 0; // up to one parameter is supported in UDAF.
          }

          @Override
          public String getName() {
            // not used as Beam SQL uses its own execution engine
            return null;
          }

          @Override
          public RelDataType getType(RelDataTypeFactory typeFactory) {
            Type inputType = getInputType();
            if (inputType instanceof TypeVariable) {
              throw new IllegalArgumentException(
                  "Unable to infer SQL type from type variable "
                      + inputType
                      + ". This usually means you are trying to use a generic type whose type information "
                      + "is not known at runtime. You can wrap your CombineFn into typed subclass"
                      + " by 'new TypedCombineFnDelegate<...>(combineFn) {}'");
            }
            return CalciteUtils.sqlTypeWithAutoCast(typeFactory, inputType);
          }

          @Override
          public boolean isOptional() {
            // not used as Beam SQL uses its own execution engine
            return false;
          }
        });
    return para;
  }

View on GitHub (pinned to 12126d8942)

Solutions

  1. Wrap the CombineFn in a typed anonymous subclass: new TypedCombineFnDelegate<InputT,AccumT,OutputT>(combineFn) {} so the concrete type parameters are preserved in the superclass signature
  2. Define the CombineFn as a concrete (non-generic) named or anonymous subclass with literal type parameters instead of passing a raw generic instance
  3. Check the class with clazz.getGenericSuperclass() instanceof ParameterizedType before registering it as a UDAF

Example fix

// before
CombineFn<Long, long[], Long> sumFn = new SumLongFn(); // raw/generic instance
sqlEnv.registerUdaf("SUM_LONG", sumFn);
// after
sqlEnv.registerUdaf("SUM_LONG", new TypedCombineFnDelegate<Long, long[], Long>(sumFn) {});
Defensive patterns

Strategy: type-guard

Validate before calling

java.util.reflect.Type t = getInputType();
if (t instanceof TypeVariable) throw new IllegalArgumentException("Wrap in TypedCombineFnDelegate<...>(fn) {}");

Type guard

static boolean hasConcreteType(CombineFn<?, ?, ?> fn) {
  return fn.getClass().getGenericSuperclass() instanceof ParameterizedType
      && Arrays.stream(fn.getClass().getSuperclass().getTypeParameters())
          .noneMatch(p -> p instanceof TypeVariable);
}

Try / catch

try {
  sqlEnv.registerUdaf(name, combineFn);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("Unable to infer SQL type")) {
    sqlEnv.registerUdaf(name, new TypedCombineFnDelegate<I, A, O>(combineFn) {});
  } else throw e;
}

Prevention

When it happens

Trigger: Registering a UDAF via UdfUtils/ReflectiveSchema whose CombineFn is a generic class or was created through a generic method, so getInputType() returns a TypeVariable instead of a concrete Class/ParameterizedType.

Common situations: Defining a CombineFn inside a generic helper method or generic class and passing it to Beam SQL UDAF registration; using a lambda or raw CombineFn reference whose type parameters were erased; registering the same generic CombineFn for multiple SQL types.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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