{"record":{"id":"fa3f52fcca6d11de","repo":"EllanJiang/GameFramework","slug":"asset-is-invalid","errorCode":null,"errorMessage":"Asset is invalid.","messagePattern":"Asset is invalid\\.","errorType":"validation","errorClass":"GameFrameworkException","httpStatus":null,"severity":"error","filePath":"GameFramework/Resource/ResourceManager.cs","lineNumber":1638,"sourceCode":"            }\n\n            if (loadAssetCallbacks == null)\n            {\n                throw new GameFrameworkException(\"Load asset callbacks is invalid.\");\n            }\n\n            m_ResourceLoader.LoadAsset(assetName, assetType, priority, loadAssetCallbacks, userData);\n        }\n\n        /// <summary>\n        /// 卸载资源。\n        /// </summary>\n        /// <param name=\"asset\">要卸载的资源。</param>\n        public void UnloadAsset(object asset)\n        {\n            if (asset == null)\n            {\n                throw new GameFrameworkException(\"Asset is invalid.\");\n            }\n\n            if (m_ResourceLoader == null)\n            {\n                return;\n            }\n\n            m_ResourceLoader.UnloadAsset(asset);\n        }\n\n        /// <summary>\n        /// 异步加载场景。\n        /// </summary>\n        /// <param name=\"sceneAssetName\">要加载场景资源的名称。</param>\n        /// <param name=\"loadSceneCallbacks\">加载场景回调函数集。</param>\n        public void LoadScene(string sceneAssetName, LoadSceneCallbacks loadSceneCallbacks)\n        {\n            if (string.IsNullOrEmpty(sceneAssetName))","sourceCodeStart":1620,"sourceCodeEnd":1656,"githubUrl":"https://github.com/EllanJiang/GameFramework/blob/d0c010b05167c58e92350449d04864a91ca13fd2/GameFramework/Resource/ResourceManager.cs#L1620-L1656","documentation":"ResourceManager.UnloadAsset(asset) throws this when the asset argument is null. Unloading requires an actual asset object (previously returned by LoadAsset's success callback); there is nothing to release for null, so the framework rejects it immediately.","triggerScenarios":"Calling UnloadAsset with a null reference — e.g. the asset field was never assigned from the load-success callback, or was already set to null after a previous unload.","commonSituations":"Storing the loaded asset in a field that was reset or cleared elsewhere; double-unload where the second call sees a nulled field; a load that failed so the success callback never populated the asset, then UnloadAsset is called in cleanup.","solutions":["Null-check the asset before calling UnloadAsset and skip the call when it is null.","Only invoke UnloadAsset from paths guaranteed to have run after a successful load callback assigned the asset.","Guard against double-unload by clearing the field after unloading and checking it before unloading."],"exampleFix":"// before\npublic void Close()\n{\n    m_ResourceManager.UnloadAsset(m_Icon);\n}\n// after\npublic void Close()\n{\n    if (m_Icon != null)\n    {\n        m_ResourceManager.UnloadAsset(m_Icon);\n        m_Icon = null;\n    }\n}","handlingStrategy":"validation","validationCode":"if (asset != null)\n{\n    m_ResourceManager.UnloadAsset(asset);\n    asset = null;\n}","typeGuard":"static bool CanUnload(object asset) => asset != null;","tryCatchPattern":"try\n{\n    m_ResourceManager.UnloadAsset(asset);\n}\ncatch (GameFrameworkException ex)\n{\n    Log.Error(\"UnloadAsset failed: {0}\", ex.Message);\n}","preventionTips":["Only assign asset fields from load-success callbacks.","Set the field to null after unloading to make double-unload checks trivial.","Null-check assets in cleanup/teardown paths where loads may have failed."],"tags":["csharp","gameframework","argument-validation","asset-unloading"],"backgroundTag":"null-argument","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"}