Correct way to create/update AnimatorController asset with UnityEditor script?

I’m creating/updating AnimatorController assets using a UnityEditor script.
When they are generated, they work fine. I can close the scene, reopen it, move states and transitions around, etc. And it looks like my states and transitions have been persisted. I even see diffs in the asset file itself.

But when I close Unity and restart it, all my states and transitions disappear.
So, it looks like Unity “thinks” the states and transitions have been persisted but it’s actually just fetching them from memory or something. Either that or it’s saving the states and transitions in a format it can’t load later…

I’m on Unity 2020.3.28f1.

This is either a bug with Unity or I’m handling AnimatorController incorrectly. Help?

When creating, I use,

AssetDatabase.CreateAsset(animatorController, outputPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();

But that doesn’t seem to persist the states and transitions properly.

Here’s a sample of the diffs after I regenerate the AnimatorController,

@@ -19,60 +19,7 @@ AnimatorStateMachine:
   m_ExitPosition: {x: 800, y: 120, z: 0}
   m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
   m_DefaultState: {fileID: 0}
---- !u!1107 &-7698584499765719767
-AnimatorStateMachine:
-  serializedVersion: 6
-  m_ObjectHideFlags: 1
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  m_Name: Base Layer
-  m_ChildStates: []
-  m_ChildStateMachines: []
-  m_AnyStateTransitions: []
-  m_EntryTransitions: []
-  m_StateMachineTransitions: {}
-  m_StateMachineBehaviours: []
-  m_AnyStatePosition: {x: 50, y: 20, z: 0}
-  m_EntryPosition: {x: 50, y: 120, z: 0}
-  m_ExitPosition: {x: 800, y: 120, z: 0}
-  m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
-  m_DefaultState: {fileID: 0}
---- !u!91 &9100000
-AnimatorController:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  m_Name: 1_m_02_AnimatorController
-  serializedVersion: 5
-  m_AnimatorParameters:
-  - m_Name: facing
-    m_Type: 3
-    m_DefaultFloat: 0
-    m_DefaultInt: 0
-    m_DefaultBool: 0
-    m_Controller: {fileID: 9100000}
-  - m_Name: state
-    m_Type: 3
-    m_DefaultFloat: 0
-    m_DefaultInt: 0
-    m_DefaultBool: 0
-    m_Controller: {fileID: 9100000}
-  m_AnimatorLayers:
-  - serializedVersion: 5
-    m_Name: Base Layer
-    m_StateMachine: {fileID: 727151397527169030}
-    m_Mask: {fileID: 0}
-    m_Motions: []
-    m_Behaviours: []
-    m_BlendingMode: 0
-    m_SyncedLayerIndex: -1
-    m_DefaultWeight: 0
-    m_IKPass: 0
-    m_SyncedLayerAffectsTiming: 0
-    m_Controller: {fileID: 9100000}
---- !u!1107 &727151397527169030
+--- !u!1107 &-8727113322944297069
AnimatorStateMachine:
   serializedVersion: 6
   m_ObjectHideFlags: 1
@@ -171,6 +118,78 @@ AnimatorStateMachine:
   m_ExitPosition: {x: 800, y: 120, z: 0}
   m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
   m_DefaultState: {fileID: 0}
+--- !u!1107 &-7698584499765719767
+AnimatorStateMachine:
+  serializedVersion: 6
+  m_ObjectHideFlags: 1
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: Base Layer
+  m_ChildStates: []
+  m_ChildStateMachines: []
+  m_AnyStateTransitions: []
+  m_EntryTransitions: []
+  m_StateMachineTransitions: {}
+  m_StateMachineBehaviours: []
+  m_AnyStatePosition: {x: 50, y: 20, z: 0}
+  m_EntryPosition: {x: 50, y: 120, z: 0}
+  m_ExitPosition: {x: 800, y: 120, z: 0}
+  m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
+  m_DefaultState: {fileID: 0}
+--- !u!91 &9100000
+AnimatorController:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: 1_m_02_AnimatorController
+  serializedVersion: 5
+  m_AnimatorParameters:
+  - m_Name: facing
+    m_Type: 3
+    m_DefaultFloat: 0
+    m_DefaultInt: 0
+    m_DefaultBool: 0
+    m_Controller: {fileID: 9100000}
+  - m_Name: state
+    m_Type: 3
+    m_DefaultFloat: 0
+    m_DefaultInt: 0
+    m_DefaultBool: 0
+    m_Controller: {fileID: 9100000}
+  m_AnimatorLayers:
+  - serializedVersion: 5
+    m_Name: Base Layer
+    m_StateMachine: {fileID: -8727113322944297069}
+    m_Mask: {fileID: 0}
+    m_Motions: []
+    m_Behaviours: []
+    m_BlendingMode: 0
+    m_SyncedLayerIndex: -1
+    m_DefaultWeight: 0
+    m_IKPass: 0
+    m_SyncedLayerAffectsTiming: 0
+    m_Controller: {fileID: 9100000}
+--- !u!1107 &727151397527169030
+AnimatorStateMachine:
+  serializedVersion: 6
+  m_ObjectHideFlags: 1
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: Base Layer
+  m_ChildStates: []
+  m_ChildStateMachines: []
+  m_AnyStateTransitions: []
+  m_EntryTransitions: []
+  m_StateMachineTransitions: {}
+  m_StateMachineBehaviours: []
+  m_AnyStatePosition: {x: 50, y: 20, z: 0}
+  m_EntryPosition: {x: 50, y: 120, z: 0}
+  m_ExitPosition: {x: 800, y: 120, z: 0}
+  m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
+  m_DefaultState: {fileID: 0}
--- !u!1107 &853159014853272647
AnimatorStateMachine:
   serializedVersion: 6

I am having the exact same problem.
I experimentally tried SaveAsset State and StateMachine and AvatarMask, and then SaveAsset AnimatorController, but nothing changed.
I want to know how to generate fileID for State, State Machine and AvaterMask.

I self-solved.
Among the members of the class group related to AnimatorController, the member array with the Add method must not be given an array that has been created with new externally.
If you do not add it with the AddXXX method, internal parameters such as fileID will not be set up.

Well, there was a problem.
Uses a saved AnimatorController asset to maintain the guid.
Then use RemoveLayer and AddLayer to set a new AnimatorControllerLayer.
As a result the AnimatorControllerLayer properties are not saved.
Even if I set StateMachine, the fileID of the StateMachine property becomes 0.
Instance of AnimatorController and Instance of AnimatorControllerLayer and Instance of AnimatorStateMachine must use the ones saved by the Editor as they are.
In this state, I have successfully merged the states and transitions of the other AnimatorControllers.
But the AnimatorControllerLayer properties are immutable. Even if it is rewritten with EditorScript, it will be ignored.
It is not reflected in the save result.

I finally figured out that I have to AssetDatabase.AddObjectToAsset() each internal object of a non-serialized in the asset.