{"record":{"id":"538f776394390442","repo":"egametang/ET","slug":"condition-node-field-not-found-node-gettype-fu","errorCode":null,"errorMessage":"condition node field not found: {node.GetType().FullName}.{fieldName}","messagePattern":"condition node field not found: (.+?)\\.(.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.conditionexpr/Scripts/Model/Share/ConditionExprParser.cs","lineNumber":275,"sourceCode":"                this.SetCompareField(condition, nameof(BTNumericCompare.ErrorCode), errorCode);\n                return;\n            }\n\n            if (node is BTNot not)\n            {\n                not.ErrorCode = errorCode;\n                return;\n            }\n\n            throw new Exception($\"condition group error code only support leaf or not node: {node.GetType().Name}\");\n        }\n\n        private void SetCompareField(BTCondition node, string fieldName, object value)\n        {\n            FieldInfo fieldInfo = node.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public);\n            if (fieldInfo == null)\n            {\n                throw new Exception($\"condition node field not found: {node.GetType().FullName}.{fieldName}\");\n            }\n\n            fieldInfo.SetValue(node, value);\n        }\n\n        private void SetOwnerKeyField(BTCondition node, string ownerKey)\n        {\n            FieldInfo fieldInfo = node.GetType().GetField(nameof(BTNumericCompare.OwnerKey), BindingFlags.Instance | BindingFlags.Public);\n            if (fieldInfo == null)\n            {\n                throw new Exception($\"condition node owner key field not found: {node.GetType().FullName}.{nameof(BTNumericCompare.OwnerKey)}\");\n            }\n\n            if (fieldInfo.FieldType != typeof(string))\n            {\n                throw new Exception($\"condition node owner key field must be string: {node.GetType().FullName}.{nameof(BTNumericCompare.OwnerKey)}\");\n            }\n","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.conditionexpr/Scripts/Model/Share/ConditionExprParser.cs#L257-L293","documentation":"Thrown by SetCompareField when reflecting a custom (non-BTNumericCompare) condition node for one of the shared compare fields (Op / Value / ErrorCode). The node type was registered via [ConditionVariable] and selected by ParseCompare, but it does not declare a public instance field with that exact name, so GetField returns null.","triggerScenarios":"Registering a custom [ConditionVariable] node that omits or renames the public `Op`, `Value`, or `ErrorCode` field; declaring the field as a property instead of a field; marking it private/protected; or declaring it on a base class that is not visible to Instance|Public binding on the concrete type.","commonSituations":"A developer adds a new condition variable type and forgets the canonical field set; a rename refactor changes `Value` to `Threshold` without updating expectations; field is auto-property (backing field is private and compiler-named).","solutions":["Add a public instance field with the exact name reported in the message (Op of type ConditionCompareOp, Value matching the numeric type, ErrorCode of type int) to the custom node class.","Use a plain public field, not an auto-property; GetField with Instance|Public will not see properties.","If you intended a BTN-style node, consider inheriting BTNumericCompare so the fields come for free."],"exampleFix":"// before\n[ConditionVariable(\"MyFlag\")]\npublic class MyFlagNode : BTCondition\n{\n    public int Threshold; // wrong name\n}\n// after\n[ConditionVariable(\"MyFlag\")]\npublic class MyFlagNode : BTCondition\n{\n    public ConditionCompareOp Op;\n    public long Value;\n    public int ErrorCode;\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// verify a custom condition node declares the required public fields\nstatic bool HasCompareFields(Type t) =>\n    t.GetField(\"Op\", BindingFlags.Instance | BindingFlags.Public) != null\n    && t.GetField(\"Value\", BindingFlags.Instance | BindingFlags.Public) != null\n    && t.GetField(\"ErrorCode\", BindingFlags.Instance | BindingFlags.Public) != null;","tryCatchPattern":null,"preventionTips":["Inherit BTNumericCompare when possible so fields come for free.","Add an assembly-scan unit test asserting every [ConditionVariable] node has Op/Value/ErrorCode public fields.","Use plain public fields, not properties, for reflectable compare fields."],"tags":["csharp","unity","conditionexpr","reflection","attribute"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}