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
- Pass the IFsm<T> reference supplied to the state's lifecycle methods (OnInit/OnEnter parameters) rather than a cached possibly-null field
- Guard the cached reference with a null check before transitioning
- 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
- Always use the IFsm<T> argument supplied to state lifecycle callbacks
- Avoid caching IFsm references in state fields
- Only transition while the state is attached to a running FSM
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)