EllanJiang/GameFramework · error · GameFrameworkException

FSM ' ' state ' ' is already exist.

Error message

FSM '{0}' state '{1}' is already exist.

What it means

Fsm<T>.Create registers each state in a dictionary keyed by the state's concrete Type. Passing two instances of the same state type fails the ContainsKey check at Fsm.cs:160 and throws this formatted exception naming the FSM and the duplicate type.

Solutions

  1. Remove the duplicate state instance so each concrete FsmState<T> subclass appears exactly once.
  2. De-duplicate by type before Create: states = states.DistinctBy(s => s.GetType()).ToList() (or a loop with a HashSet<Type>).
  3. If you need the same behavior in two states, extract shared logic into a common base class and create two distinct subclasses.

Example fix

// before
var fsm = Fsm<Enemy>.Create("Enemy", this, new IdleState(), new IdleState());
// after
var fsm = Fsm<Enemy>.Create("Enemy", this, new IdleState());
Defensive patterns

Strategy: validation

Validate before calling

var seen = new HashSet<Type>();
foreach (var s in states)
{
    if (!seen.Add(s.GetType()))
        throw new InvalidOperationException($"Duplicate state type {s.GetType().Name}.");
}
var fsm = Fsm<Enemy>.Create("Enemy", this, states);

Type guard

bool HasNoDuplicateStates<T>(IEnumerable<FsmState<T>> states) where T : class => states.Select(s => s.GetType()).Distinct().Count() == states.Count();

Try / catch

try { fsm = Fsm<Enemy>.Create("Enemy", this, states); }
catch (GameFrameworkException ex) { Log.Error("Duplicate FSM state: " + ex.Message); }

Prevention

When it happens

Trigger: Fsm<T>.Create(name, owner, new StateA(), new StateA()) — any duplicated concrete FsmState<T> subclass in the params array or List overload input.

Common situations: Programmatically generating the state list (e.g. one instance per enum flag) where a flag maps to the same state class twice; copy-paste duplicating a state in the Create call; merging two state lists without de-duplicating.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of EllanJiang/GameFramework@d0c010b051 (2026-09-15). Data as JSON: /api/errors/5d8e9accef6b50e4. Report an issue: GitHub.

Appendix: source

Thrown at GameFramework/Fsm/Fsm.cs:160

            {
                throw new GameFrameworkException("FSM states is invalid.");
            }

            Fsm<T> fsm = ReferencePool.Acquire<Fsm<T>>();
            fsm.Name = name;
            fsm.m_Owner = owner;
            fsm.m_IsDestroyed = false;
            foreach (FsmState<T> state in states)
            {
                if (state == null)
                {
                    throw new GameFrameworkException("FSM states is invalid.");
                }

                Type stateType = state.GetType();
                if (fsm.m_States.ContainsKey(stateType))
                {
                    throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name), stateType.FullName));
                }

                fsm.m_States.Add(stateType, state);
                state.OnInit(fsm);
            }

            return fsm;
        }

        /// <summary>
        /// 创建有限状态机。
        /// </summary>
        /// <param name="name">有限状态机名称。</param>
        /// <param name="owner">有限状态机持有者。</param>
        /// <param name="states">有限状态机状态集合。</param>
        /// <returns>创建的有限状态机。</returns>
        public static Fsm<T> Create(string name, T owner, List<FsmState<T>> states)
        {

View on GitHub (pinned to d0c010b051)