{"record":{"id":"462b9b0ef2f492f2","repo":"EllanJiang/GameFramework","slug":"state-type-0-is-invalid-fsmstate","errorCode":null,"errorMessage":"State type '{0}' is invalid.","messagePattern":"State type '(.+?)' is invalid\\.","errorType":"exception","errorClass":"GameFrameworkException","httpStatus":null,"severity":"error","filePath":"GameFramework/Fsm/FsmState.cs","lineNumber":104,"sourceCode":"        /// </summary>\n        /// <param name=\"fsm\">有限状态机引用。</param>\n        /// <param name=\"stateType\">要切换到的有限状态机状态类型。</param>\n        protected void ChangeState(IFsm<T> fsm, Type stateType)\n        {\n            Fsm<T> fsmImplement = (Fsm<T>)fsm;\n            if (fsmImplement == null)\n            {\n                throw new GameFrameworkException(\"FSM is invalid.\");\n            }\n\n            if (stateType == null)\n            {\n                throw new GameFrameworkException(\"State type is invalid.\");\n            }\n\n            if (!typeof(FsmState<T>).IsAssignableFrom(stateType))\n            {\n                throw new GameFrameworkException(Utility.Text.Format(\"State type '{0}' is invalid.\", stateType.FullName));\n            }\n\n            fsmImplement.ChangeState(stateType);\n        }\n    }\n}\n","sourceCodeStart":86,"sourceCodeEnd":111,"githubUrl":"https://github.com/EllanJiang/GameFramework/blob/d0c010b05167c58e92350449d04864a91ca13fd2/GameFramework/Fsm/FsmState.cs#L86-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nfsm.ChangeState(typeof(PlayerState)); // PlayerState : FsmState<Enemy> (wrong owner)\n\n// after\npublic class PlayerState : FsmState<Player> { }\nfsm.ChangeState(typeof(PlayerState)); // matches Fsm<Player> owner type","handlingStrategy":"validation","validationCode":"if (stateType == null || !typeof(FsmState<T>).IsAssignableFrom(stateType))\n    throw new ArgumentException($\"{stateType} is not a valid FsmState<T> for this FSM\");","typeGuard":"static bool IsValidFsmState<T>(Type t) => t != null && typeof(FsmState<T>).IsAssignableFrom(t);","tryCatchPattern":"try { fsm.ChangeState(typeof(MyState)); }\ncatch (GameFrameworkException ex) { Log.Error(\"Invalid state type: \" + ex.Message); }","preventionTips":["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."],"tags":["fsm","state-machine","type-mismatch"],"backgroundTag":"incompatible-source-type","analyzedSha":"d0c010b05167c58e92350449d04864a91ca13fd2","analyzedAt":"2026-09-15T13:37:15.352Z","contentChangedAt":"2026-09-15T13:37:15.352Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}