xai-org/x-algorithm · error · SemanticCheckFailure

Cannot create StructTuple Type without a fieldName list.

Error message

Cannot create StructTuple Type without a fieldName list.

What it means

Type.of constructs a Type from a raw class plus type parameters. StructTuple requires an explicit field-name list, so constructing it via Type.of with type params but no names is rejected with SemanticCheckFailure.

Source

Thrown at botmaker/src/java/com/twitter/botmaker/compiler/types/Type.java:332

  public static ThriftStructType thriftStructOf(
      Class<? extends ThriftStruct> typeBase) {
    return ThriftStructType.ofThriftStruct(typeBase);
  }

  static Type of(Class<?> typeBase, ImmutableList<Type> typeParams)
      throws SemanticCheckFailure {
    if (List.class.isAssignableFrom(typeBase) && typeParams.size() == 1) {
      return listOf(typeParams.get(0));
    } else if (Set.class.isAssignableFrom(typeBase) && typeParams.size() == 1) {
      return setOf(typeParams.get(0));
    } else if (Collection.class.isAssignableFrom(typeBase) && typeParams.size() == 1) {
      return collectionOf(typeParams.get(0));
    } else if (Map.class.isAssignableFrom(typeBase) && typeParams.size() == 2) {
      return mapOf(typeParams.get(0), typeParams.get(1));
    } else if (Pair.class.isAssignableFrom(typeBase) && typeParams.size() == 2) {
      return pairOf(typeParams.get(0), typeParams.get(1));
    } else if (StructTuple.class.isAssignableFrom(typeBase) && typeParams.size() > 0) {
      throw new SemanticCheckFailure(
          "Cannot create StructTuple Type without a fieldName list.");
    } else if (Tuple.class.isAssignableFrom(typeBase) && typeParams.size() > 0) {
      return tupleOf(typeParams.toArray(new Type[]{}));
    } else if (TBase.class.isAssignableFrom(typeBase) && typeParams.size() == 0) {
      return thriftOf((Class<? extends TBase>) typeBase);
    } else if (TEnum.class.isAssignableFrom(typeBase) && typeParams.size() == 0) {
      return thriftEnumOf((Class<? extends TEnum>) typeBase);
    } else if (ThriftStruct.class.isAssignableFrom(typeBase) && typeParams.size() == 0) {
      return thriftStructOf((Class<? extends ThriftStruct>) typeBase);
    } else if (ByteBuffer.class.isAssignableFrom(typeBase) && typeParams.size() == 0) {
      return Type.BINARY;
    } else if (PRIMITIVE_TYPES.containsKey(typeBase) && typeParams.size() == 0) {
      return PRIMITIVE_TYPES.get(typeBase);
    } else {
      return Type.of(typeBase, typeParams, Serializer.OBJECT);
    }
  }

View on GitHub (pinned to 24c60942c5)

Solutions

  1. Use the dedicated StructTuple factory (e.g. Type.structTupleOf(class, fieldNames, types...)) that supplies field names
  2. Avoid Type.of for StructTuple; reserve it for Tuple/Map/Pair/thrift types
  3. Pass a field-name list alongside the element types

Example fix

// before
Type t = Type.of(MyTuple.class, Type.INT, Type.STRING);
// after
Type t = Type.structTupleOf(MyTuple.class,
    ImmutableList.of("id", "name"), Type.INT, Type.STRING);
Defensive patterns

Strategy: validation

Validate before calling

if (StructTuple.class.isAssignableFrom(typeBase)) {
  throw new IllegalArgumentException("use structTupleOf with field names");
}

Try / catch

catch SemanticCheckFailure 'Cannot create StructTuple Type' and switch to the field-name-aware factory

Prevention

When it happens

Trigger: Type.of(StructTuple.class, someTypes...) or reflective construction paths (listOf/setOf/collectionOf/pairOf/mapOf falling through) that hit the StructTuple branch — i.e. building a StructTuple Type without the (Class, List<String>, Type...) overload.

Common situations: See trigger scenarios.

Related errors


AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28). Data as JSON: /api/errors/eeb13df26e8983a0. Report an issue: GitHub.