xai-org/x-algorithm · error · SemanticCheckFailure
class to be imported has to be either a TBase or ThriftStruc
Error message
class to be imported has to be either a TBase or ThriftStruct: %s.
What it means
The `import` statement in a Botmaker expression must reference a Thrift-generated type. TypeCompiler resolved the class, but it was neither a ThriftType (TBase) nor a ThriftStructType, so the compiler refuses to bind it into the type context.
Source
Thrown at botmaker/src/java/com/twitter/botmaker/compiler/Compiler.java:710
try {
ASTNode node = createASTNodeTree(context, child);
return ToThrift.mkNewThriftObject(exprText, className, node);
} catch (Exception e) {
throw new SemanticCheckFailure(e);
}
}
private ASTNode toImport(CompilerContext context, Tree root) throws SemanticCheckFailure {
String clsName = getFullName(root);
String alias = root.getChild(root.getChildCount() - 1).getText();
Type type = TypeCompiler.getTypeFromClassName(clsName);
if (type instanceof ThriftType) {
context.defineType((ThriftType) type, alias);
} else if (type instanceof ThriftStructType) {
context.defineType((ThriftStructType) type, alias);
} else {
throw new SemanticCheckFailure(
String.format(
"class to be imported has to be either a TBase or ThriftStruct: %s.", clsName)
);
}
return Constant.UNIT;
}
private ASTNode toImportAs(CompilerContext context, Tree root) throws SemanticCheckFailure {
String cls = getFullName(root, root.getChildCount() - 1);
String alias = root.getChild(root.getChildCount() - 1).getText();
Class<?> clazz;
try {
clazz = ClassCache.forName(cls);
} catch (Exception e) {
throw new SemanticCheckFailure(View on GitHub (pinned to 24c60942c5)
Solutions
- Replace the imported class with a Thrift-generated TBase or ThriftStruct class
- Regenerate the Thrift/Scrooge classes with the codegen version matching the Botmaker runtime
- Verify the class is on the compile classpath and is the generated struct, not a hand-written wrapper
Example fix
// before
import("com.example.MyPlainPojo", pojo)
// after
import("com.example.thriftscala.MyThriftStruct", myStruct) Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = ClassCache.forName(clsName); if (!TBase.class.isAssignableFrom(c) && !ThriftStruct.class.isAssignableFrom(c)) throw new IllegalArgumentException(clsName + " is not a Thrift type");
Type guard
static boolean isImportableThriftType(Class<?> c) {
return TBase.class.isAssignableFrom(c) || ThriftStruct.class.isAssignableFrom(c);
} Try / catch
catch (SemanticCheckFailure e) { /* surface import name and fix config */ } Prevention
- Only import generated Thrift structs
- Pin thrift codegen version to the runtime version
When it happens
Trigger: Using `import("com.example.SomeClass", alias)` where SomeClass is a plain Java class, an interface, or a Thrift class generated by an incompatible codegen version.
Common situations: Trying to import java.lang or guava classes, importing a Thrift struct compiled against a mismatched thrift/scrooge runtime, or importing a class not on the compiler's classpath (which may resolve to a stub).
Related errors
- cannot find class %s
- Sort expects a collection of %s objects, but gets %s
- Parameter [%s] type [%s] is not compatible with the default
- ASTNode return type [%s] is not compatible with the claimed
- type cannot defined in root scope: %s
AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28).
Data as JSON: /api/errors/06c91857295a8987.
Report an issue: GitHub.