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.

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.

Appendix: 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)