egametang/ET · critical · Exception

duplicate condition variable

Error message

duplicate condition variable: {conditionVariableAttribute.Variable}

What it means

Thrown during ConditionVariableRegistry.Awake() when TryAdd fails, meaning two [ConditionVariable] registrations (or a registration colliding with a built-in NumericType name) claimed the same variable string. The registry is a single Dictionary keyed by variable name, so duplicates are rejected to keep parser lookup unambiguous.

Solutions

  1. Rename one of the conflicting variables so each name maps to exactly one node type.
  2. If colliding with a NumericType name, pick a different custom variable name or remove the redundant custom node.
  3. Search the codebase for `[ConditionVariable("<name>")]` and the NumericType enum to find both sources.

Example fix

// before
[ConditionVariable("HP")]
public class CustomHpNode : BTCondition { }
// (HP already a NumericType)
// after
[ConditionVariable("CustomHp")]
public class CustomHpNode : BTCondition { }
Defensive patterns

Strategy: validation

Validate before calling

// detect duplicate variable names at startup before the registry throws
var seen = new HashSet<string>();
foreach (Type t in CodeTypes.Instance.GetTypes(typeof(ConditionVariableAttribute)))
    foreach (ConditionVariableAttribute a in t.GetCustomAttributes(typeof(ConditionVariableAttribute), false))
        if (!seen.Add(a.Variable))
            Console.Error.WriteLine($"duplicate condition variable: {a.Variable} on {t.FullName}");

Prevention

When it happens

Trigger: Two node classes both declare `[ConditionVariable("HP")]`; a custom variable name collides with a registered NumericType enum name (RegisterNumericTypes pre-registers each NumericType name pointing at BTNumericCompare).

Common situations: Renaming a node and forgetting the old one still carries the same attribute; introducing a new NumericType enum member whose name clashes with an existing custom variable.

Related errors


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/73e23e9a173ca2f7. Report an issue: GitHub.

Appendix: source

Thrown at Packages/cn.etetet.conditionexpr/Scripts/Model/Share/ConditionVariableRegistry.cs:36

            foreach (Type type in types)
            {
                if (!typeof(BTCondition).IsAssignableFrom(type))
                {
                    throw new Exception($"condition variable node must inherit BTCondition: {type.FullName}");
                }

                object[] attrs = type.GetCustomAttributes(typeof(ConditionVariableAttribute), false);
                foreach (object attr in attrs)
                {
                    ConditionVariableAttribute conditionVariableAttribute = (ConditionVariableAttribute)attr;
                    if (string.IsNullOrWhiteSpace(conditionVariableAttribute.Variable))
                    {
                        throw new Exception($"condition variable is empty: {type.FullName}");
                    }

                    if (!this.variableNodeTypes.TryAdd(conditionVariableAttribute.Variable, type))
                    {
                        throw new Exception($"duplicate condition variable: {conditionVariableAttribute.Variable}");
                    }
                }
            }
        }

        private void RegisterNumericTypes()
        {
            foreach (NumericType numericType in Enum.GetValues(typeof(NumericType)))
            {
                string variable = numericType.ToString();
                this.numericTypes.Add(variable, numericType);
                this.variableNodeTypes.Add(variable, typeof(BTNumericCompare));
            }
        }

        public bool TryGetNodeType(string variable, out Type nodeType)
        {
            return this.variableNodeTypes.TryGetValue(variable, out nodeType);

View on GitHub (pinned to 5cab01f7a8)