{"record":{"id":"328a7acfeb8499fc","repo":"apache/beam","slug":"expected-thrift-class-but-got-s","errorCode":null,"errorMessage":"Expected thrift class but got: %s","messagePattern":"Expected thrift class but got: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/thrift/src/main/java/org/apache/beam/sdk/io/thrift/ThriftSchema.java","lineNumber":173,"sourceCode":"    }\n\n    public @NonNull SchemaProvider provider() {\n      if (typedefs.isEmpty()) {\n        return defaultProvider;\n      } else {\n        return new ThriftSchema(unmodifiableMap(new HashMap<>(typedefs)));\n      }\n    }\n  }\n\n  @Override\n  public <T> @NonNull Schema schemaFor(TypeDescriptor<T> typeDescriptor) {\n    return schemaFor(typeDescriptor.getRawType());\n  }\n\n  private Schema schemaFor(Class<?> targetClass) {\n    if (!TBase.class.isAssignableFrom(targetClass)) {\n      throw new IllegalArgumentException(\"Expected thrift class but got: \" + targetClass);\n    }\n    final Stream<Schema.Field> fields =\n        thriftFieldDescriptors(targetClass).values().stream().map(this::beamField);\n    if (TUnion.class.isAssignableFrom(targetClass)) {\n      // Beam OneOf is just a record of fields where exactly one must be non-null, so it doesn't\n      // allow the types of the cases to be nullable\n      return OneOfType.create(fields.map(f -> f.withNullable(false)).collect(Collectors.toList()))\n          .getOneOfSchema();\n    } else {\n      return fields\n          .reduce(Schema.builder(), Schema.Builder::addField, ThriftSchema::throwingCombiner)\n          .build();\n    }\n  }\n\n  private static <X> X throwingCombiner(X lhs, X rhs) {\n    throw new IllegalStateException();\n  }","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/thrift/src/main/java/org/apache/beam/sdk/io/thrift/ThriftSchema.java#L155-L191","documentation":"ThriftSchema.schemaFor builds a Beam Schema from a thrift class but first requires the target class to implement TBase. If a non-thrift class is passed, an IllegalArgumentException with this message is thrown.","triggerScenarios":"Passing a TypeDescriptor or Class that is not a generated thrift struct (e.g. a plain POJO or the wrong type parameter) to ThriftSchema.provider().schemaFor(...) or a ThriftIO transform expecting a thrift class.","commonSituations":"Refactoring pipeline types and accidentally wiring a POJO where a generated thrift struct belongs; using the raw generic type instead of the concrete TBase subclass.","solutions":["Pass a class generated by the thrift compiler (extends TBase), e.g. com.example.thrift.ThriftRecord","Check the generic/raw type being forwarded — schemaFor(getRawType()) may be receiving Object or a wrapper","If the element type should be a POJO, use the standard Schema inference instead of ThriftSchema"],"exampleFix":"// before\nSchema s = ThriftSchema.provider().schemaFor(TypeDescriptor.of(MyPojo.class)); // not TBase\n// after\nSchema s = ThriftSchema.provider().schemaFor(TypeDescriptor.of(com.example.thrift.ThriftRecord.class));","handlingStrategy":"type-guard","validationCode":"if (!TBase.class.isAssignableFrom(ThriftRecord.class)) { throw new IllegalArgumentException(\"element type must be a thrift-generated TBase\"); }","typeGuard":"static <T> boolean isThriftType(Class<T> c) { return TBase.class.isAssignableFrom(c); }","tryCatchPattern":"try { schema = ThriftSchema.provider().schemaFor(td); } catch (IllegalArgumentException e) { throw new IllegalStateException(\"Pass a thrift-generated class, not \" + td.getRawType(), e); }","preventionTips":["Type transforms as PCollection<? extends TBase> so misuse is caught at compile time","Avoid raw TypeDescriptor.of(Object.class) forwarding","Use the standard schema framework for non-thrift POJOs"],"tags":["java","thrift","schema","type-check"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}