{"record":{"id":"8094acce07fe3a68","repo":"xai-org/x-algorithm","slug":"field-name-s-has-to-be-a-string","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/ThriftOperator.java","lineNumber":78,"sourceCode":"\n  public static void checkThriftFieldTypes(\n      ThriftType 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":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/xai-org/x-algorithm/blob/24c60942c5c5fdad3a6addffb4c6e6d2f228f04f/botmaker/src/java/com/twitter/botmaker/function/thrift/ThriftOperator.java#L60-L96","documentation":"ThriftOperator.checkThriftFieldTypes throws SemanticCheckFailure when the first child of a (fieldName, value) argument pair is a Constant whose value is not a String. Thrift field-setting operators name fields with string literals; non-string constants (numbers, booleans) are rejected.","triggerScenarios":"Constructing a thrift operator call with a non-string constant as the field name, e.g. ThriftOperator with children (Constant(1), valueNode) instead of (Constant(\"fieldName\"), valueNode).","commonSituations":"Code-generated expressions that emit numeric field IDs instead of names, typos where the value node comes first, expression-builder bugs swapping argument order.","solutions":["Ensure the first argument of each pair is a String constant naming the thrift field","Check argument ordering: field name literal first, value expression second","If generating expressions programmatically, assert the constant is a String at build time"],"exampleFix":"// before\nchildren = [Constant(1), valueNode]\n// after\nchildren = [Constant(\"userId\"), 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(\"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  ThriftOperator.of(...);\n} catch (SemanticCheckFailure e) {\n  // surface argument pair index and constant value for debugging\n}","preventionTips":["Always emit field names as string literals in expression builders","Enforce (name, value) pair ordering with builder APIs","Test codegen against a sample thrift struct for every operator"],"tags":["thrift","field-name","type-mismatch","semantic-check"],"backgroundTag":"thrift-field-name-not-string","analyzedSha":"24c60942c5c5fdad3a6addffb4c6e6d2f228f04f","analyzedAt":"2026-08-28T11:40:14.686Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}