If you use GetProgramVariable on an UdonBehaviour immediately after it has been initialized via VRCInstantate.Instantiate, it will return null for valid variable names since the heap has not been initialized yet. In order for the heap to be valid you need to wait for the UdonBehaviour's first update for the variables to be valid. Another case where GetProgramVariable will fail is if the UdonBehaviour is disabled and has never been enabled.
In a similar vein, if you set any heap variable via SetProgramVariable() before its heap has had a chance to initialize, SetProgramVariable will silently fail and any attempts to get the variable via GetProgramVariable() before initialization after setting it will return null.
It would be good if these functions (SetProgramVariable, GetProgramVariable, and SendCustomEvent, along with possibly SendCustomNetworkEvent) would force the UdonBehaviour to initialize itself if it hasn't already been initialized before they execute any logic. Right now it's unexpected behavior for people who instantiate game objects; I've seen a number of people run into issues with this already and need to work around it by delaying initializing the instantiated object by a frame which gets messy very quickly and requires them to register an Update function in cases where they may not need to otherwise or they need to move their initialization logic that depends on the initializer into the initializee which means they have a difficult time determining what behaviour instantiated them. It will probably also be confusing if people try to interact with a disabled component.