EllanJiang/GameFramework · error · GameFrameworkException

FSM is invalid.

Error message

FSM is invalid.

What it means

FsmState<T>.ChangeState<TState>(IFsm<T> fsm) casts the fsm interface to the concrete Fsm<T> and delegates the transition. The library throws GameFrameworkException("FSM is invalid.") when the cast produces null — i.e. the passed IFsm<T> reference is null.

Solutions

  1. Pass the IFsm<T> reference supplied to the state's lifecycle methods (OnInit/OnEnter parameters) rather than a cached possibly-null field
  2. Guard the cached reference with a null check before transitioning
  3. Ensure the state is only used while attached to a running FSM

Example fix

// before
protected override void OnUpdate(IFsm<Player> fsm, float elapseSeconds, float realElapseSeconds)
{
    cachedFsm.ChangeState<DeadState>(cachedFsm); // cachedFsm may be null
}
// after
protected override void OnUpdate(IFsm<Player> fsm, float elapseSeconds, float realElapseSeconds)
{
    fsm.ChangeState<DeadState>(fsm); // use the provided reference
}
Defensive patterns

Strategy: validation

Validate before calling

if (fsm != null)
    ChangeState<TState>(fsm);

Type guard

static bool IsUsableFsm<T>(IFsm<T> fsm) where T : class => fsm is Fsm<T>;

Try / catch

try { ChangeState<DeadState>(fsm); }
catch (GameFrameworkException ex) { Log.Error("ChangeState failed: {0}", ex.Message); }

Prevention

When it happens

Trigger: Calling ChangeState<TState>(null) from inside a state's OnUpdate/OnEnter — the null check after the (Fsm<T>) cast fires.

Common situations: Storing the IFsm reference in the state and it was never set; calling ChangeState outside a live FSM context (state not attached to a running FSM); lifecycle ordering bugs where the state fires before FSM injection.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at GameFramework/Fsm/FsmState.cs:78

        /// <summary>
        /// 有限状态机状态销毁时调用。
        /// </summary>
        /// <param name="fsm">有限状态机引用。</param>
        protected internal virtual void OnDestroy(IFsm<T> fsm)
        {
        }

        /// <summary>
        /// 切换当前有限状态机状态。
        /// </summary>
        /// <typeparam name="TState">要切换到的有限状态机状态类型。</typeparam>
        /// <param name="fsm">有限状态机引用。</param>
        protected void ChangeState<TState>(IFsm<T> fsm) where TState : FsmState<T>
        {
            Fsm<T> fsmImplement = (Fsm<T>)fsm;
            if (fsmImplement == null)
            {
                throw new GameFrameworkException("FSM is invalid.");
            }

            fsmImplement.ChangeState<TState>();
        }

        /// <summary>
        /// 切换当前有限状态机状态。
        /// </summary>
        /// <param name="fsm">有限状态机引用。</param>
        /// <param name="stateType">要切换到的有限状态机状态类型。</param>
        protected void ChangeState(IFsm<T> fsm, Type stateType)
        {
            Fsm<T> fsmImplement = (Fsm<T>)fsm;
            if (fsmImplement == null)
            {
                throw new GameFrameworkException("FSM is invalid.");
            }

View on GitHub (pinned to d0c010b051)