{"record":{"id":"636347e43ad35f84","repo":"xai-org/x-algorithm","slug":"field-name-s-has-to-be-a-string-636347","errorCode":null,"errorMessage":"field name %s has to be a String.","messagePattern":"field name (.+?) has to be a String\\.","errorType":"validation","errorClass":"SemanticCheckFailure","httpStatus":null,"severity":"error","filePath":"botmaker/src/java/com/twitter/botmaker/function/thrift/ThriftStructOperator.java","lineNumber":77,"sourceCode":"\n  public static void checkThriftFieldTypes(\n      ThriftStructType type, List<ASTNode> nodes) throws SemanticCheckFailure {\n    for (ASTNode node : nodes) {\n      if (!(node instanceof ToPair)) {\n        continue;\n      }\n\n      ToPair pair = (ToPair) node;\n      ASTNode first = pair.getChildren().get(0);\n      ASTNode second = pair.getChildren().get(1);\n\n      if (!(first instanceof Constant)) {\n        continue;\n      }\n\n      Object value = ((Constant) first).getValue();\n      if (!(value instanceof String)) {\n        throw new SemanticCheckFailure(\n            String.format(\"field name %s has to be a String.\", value)\n        );\n      }\n\n      String fieldName = (String) value;\n      Type fieldType = type.getFieldType(fieldName);\n      if (isDivergentTo(fieldType, second)) {\n        throw new SemanticCheckFailure(\n            String.format(\"field %s expects %s type but %s received.\",\n                fieldName, fieldType, second.getReturnType()));\n      }\n    }\n  }\n\n  private static boolean isDivergentTo(\n      Type fieldType, ASTNode<?> node) throws SemanticCheckFailure {\n\n    if (fieldType.typeBase == Set.class && node instanceof SetOperator) {","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/xai-org/x-algorithm/blob/24c60942c5c5fdad3a6addffb4c6e6d2f228f04f/botmaker/src/java/com/twitter/botmaker/function/thrift/ThriftStructOperator.java#L59-L95","documentation":"ThriftStructOperator.checkThriftFieldTypes throws SemanticCheckFailure when a (fieldName, value) pair's first element is a Constant that is not a String — identical semantics to ThriftOperator but for struct-construction operators. Field names must be string literals.","triggerScenarios":"Building a thrift struct expression with a non-string constant field name, e.g. ThriftStructOperator children (Constant(3.14), value) or (Constant(true), value).","commonSituations":"Expression generators using field IDs or enums instead of names, swapped argument pairs, copy-paste from value nodes into the name slot.","solutions":["Make the first element of every pair a String constant with the exact thrift field name","Verify argument pair ordering in your expression builder","Add build-time assertions that names are String constants"],"exampleFix":"// before\nchildren = [Constant(true), valueNode]\n// after\nchildren = [Constant(\"enabled\"), valueNode]\n","handlingStrategy":"validation","validationCode":"for (int i = 0; i + 1 < children.size(); i += 2) {\n  ASTNode first = children.get(i);\n  if (first instanceof Constant && !(((Constant) first).getValue() instanceof String)) {\n    throw new IllegalArgumentException(\"struct field name must be a String constant\");\n  }\n}","typeGuard":"public static boolean isStringConstant(ASTNode n) {\n  return n instanceof Constant && ((Constant) n).getValue() instanceof String;\n}","tryCatchPattern":"try {\n  ThriftStructOperator.of(...);\n} catch (SemanticCheckFailure e) {\n  // report offending constant value and pair index\n}","preventionTips":["Use typed builder methods like withField(String name, ASTNode value)","Never reuse value nodes in the field-name slot","Property-test that all generated struct expressions pass semantic check"],"tags":["thrift","struct","field-name","type-mismatch"],"backgroundTag":"thrift-field-name-not-string","analyzedSha":"24c60942c5c5fdad3a6addffb4c6e6d2f228f04f","analyzedAt":"2026-08-28T11:40:14.686Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}