A couple of things to note: you don’t need to mark ScriptableObject-derived object types as Serializable- same with MonoBehaviours and StateMachineBehaviours. Also, you don’t need to mark public fields with SerializeField- only bother with that if they’re private or protected but you want to expose them to the inspector / be able to influence them from the custom inspector / editor window more easily. The struct definition also needs to be Serializable, not SerializeField- it’s not a field.
As to your specific problem, the issue essentially boils down to this: the object you’re referencing ceases to exist when the scene changes, or when Unity is shut down. It’s created when the scene is loaded, then destroyed when the scene is unloaded, and when loaded again a brand-new instance of the object is made again with identical data. The reference you’re generating is tied to only that specific instance of the GameObject, which is why it’s typically said that you can’t store references to scene objects in assets (“assets” includes ScriptableObjects). There are a few different ways to work around this issue.
1: Add a unique object identity to the object which differentiates it between others in the scene, so that it can be sought out and the new instance re-referenced when the scene is reloaded. This means you don’t store the reference, just the data required to get the reference again when needed.
2: Have the GameObject register itself to the asset when it’s loaded. Not much different from 1, but the GameObject (more accurately, a behaviour on it) is responsible for re-forging the connection when it’s lost rather than the asset. The reference will always be null when the scene’s not loaded.
3: Store the reference using the underlying " LocalIdentifierInFile " (which is not really trivial, it’s essentially a hack). I really really dislike this, and none of it is documented so it can be changed at any time and just stop working when you update Unity, with no additional workarounds possible.
4: Completely change your mindset about how GameObjects and Assets interact.
Option 4 is what I would go with. Assets just store data, and that data shouldn’t have any knowledge of how it’s implemented. Storing dialogue nodes (for instance) in a ScriptableObject is completely standard, but it shouldn’t care how it’s being used in the game any more than your character data should be in charge of how your avatar moves- the responsibilities are being skewed. If you need to take scene data and then save that back to be stored in an asset, then do it using some form of identification, and make sure the data isn’t tied to any specific instances of any scene objects (store Vector3s, not Transforms).
The onus should be on the GameObject (or, more accurately, on one of its behaviours) to know what identity it should be saving data into an asset as, and once the save operation is complete there should be no connection between Data and Usage beyond that simple identifier. Please note that the identifier doesn’t necessarily need to be a number, or a string, but can instead be an asset, a ScriptableObject. Some developers will create an “identity” SO for each character in the game, for each unique item in the game, for each quest in the game, for each achievement in the game, etc… This makes it possible for scene objects to hold a reference to their own “data identity”, and use that as a parameter when calling functions dealing with data, rather than behaviours. It also allows you to separate “data” from “behaviours” in a clean manner so your scene objects aren’t lugging around a ton of baggage they don’t need to do their jobs, and all of the data is one place for easier save and load operations.
Just some thoughts- everyone does things differently, so don’t take it as gospel, but maybe some of it will help you decide how best to solve your particular issue.