EllanJiang/GameFramework · error · GameFrameworkException
State type ' ' is invalid.
Error message
State type '{0}' is invalid. What it means
Thrown by the FSM extension's ChangeState when the requested state type is not a valid FSM state. It fires in two cases covered by the surrounding checks: the state type is null ("State type is invalid") or it does not derive from FsmState<T> for the FSM's owner type T. GameFramework requires every state in an Fsm<T> to inherit from FsmState<T> so lifecycle methods (OnInit, OnEnter, OnUpdate, OnLeave) can be invoked safely.
Solutions
- Make the state class inherit from FsmState<T> using exactly the same owner type T as the FSM, e.g. public class MyState : FsmState<MyOwner>.
- Verify the argument passed to ChangeState is typeof(MyState) of the correct state class, not null or a base/interface type.
- If resolving types from strings/assemblies, check the resolved type with typeof(FsmState<T>).IsAssignableFrom(resolvedType) before calling ChangeState.
Example fix
// before
fsm.ChangeState(typeof(PlayerState)); // PlayerState : FsmState<Enemy> (wrong owner)
// after
public class PlayerState : FsmState<Player> { }
fsm.ChangeState(typeof(PlayerState)); // matches Fsm<Player> owner type Defensive patterns
Strategy: validation
Validate before calling
if (stateType == null || !typeof(FsmState<T>).IsAssignableFrom(stateType))
throw new ArgumentException($"{stateType} is not a valid FsmState<T> for this FSM"); Type guard
static bool IsValidFsmState<T>(Type t) => t != null && typeof(FsmState<T>).IsAssignableFrom(t);
Try / catch
try { fsm.ChangeState(typeof(MyState)); }
catch (GameFrameworkException ex) { Log.Error("Invalid state type: " + ex.Message); } Prevention
- Always define states as public class X : FsmState<OwnerType> with the owner type matching the FSM.
- Use the generic ChangeState<MyState>() overload where available so the compiler checks the type.
- When resolving state types dynamically, run IsAssignableFrom checks before ChangeState.
When it happens
Trigger: Calling FsmExtension.ChangeState<T>(fsm, stateType) or ChangeState(fsm, stateType, userData) where stateType is null, where stateType is a non-FsmState class (e.g. a plain class or interface type), or where the state derives from FsmState<OtherOwner> while the FSM is Fsm<T> with a different owner type.
Common situations: Typo or refactoring passing the wrong Type object; passing typeof(SomeBaseClass) that only implements a similar interface; copy-pasting states across FSMs with different owner types so the generic parameter no longer matches; loading state types dynamically by name and getting an unrelated type.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- State type is invalid.
- State type ' ' is invalid.
- Current state is invalid.
- FSM ' ' can not change state to ' ' which is not exist.
- FSM is invalid.
AI-assisted analysis of EllanJiang/GameFramework@d0c010b051 (2026-09-15).
Data as JSON: /api/errors/462b9b0ef2f492f2.
Report an issue: GitHub.
Appendix: source
Thrown at GameFramework/Fsm/FsmState.cs:104
/// </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.");
}
if (stateType == null)
{
throw new GameFrameworkException("State type is invalid.");
}
if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
{
throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
}
fsmImplement.ChangeState(stateType);
}
}
}
View on GitHub (pinned to d0c010b051)