This is an issue (or aggregation of issues) in the sense that the approach to reading/writing the tool uses limits its usability with several real-world Beckhoff PLC applications I came across, more than it being some kind of a direct bug or error.
Firstly, I have several PLC application at hand (third party but also some of my own) that declare persistant variables somewhere inside function blocks or even nested function blocks within multiple instance function blocks that do not have "IsPersistent" flag at top level, but neither would it make sense nor be appropriate to read them out as objects at top structure level, because it would mean we would read out variables -and potentially write them back - that were not designed to be persistent by the software engineer. (Note that this might inherently not be problematic since all it would require is a subsequent PLC restart to loose the non-persistent variable values, but anyway that's just something to be aware of.)
So ... several persistent variables in real-world applications using function blocks, nested UDTs and other OOP approaches are not taken care of by the TwinCatAdsTool. (But they could be with a non-complicated addition - please read on.)
Secondly, persistant variable backups are often used, for security reasons (meaning from the possibility of loosing vital setting values, recipe data and similar) when upgrades are made to PLC programs. That includes changes to UDT/structure or function block changes. With the approach used for writing in the TwinCatAdsTool - or specifically the underlying TwinCar.JsonExtension WriteJson / WriteRecursive if there are new elements added to structure / FB definitions on the PLC, which are not not in the previously saved json file, then a "Null object cannot be converted to a value type" is produced. (Beckhoff's own local approach using the .bootdata file for backup does not have this problem in such situations for example.)
So ... json file backup produced with TwinCarAdsTool can't be used to write values back to the PLC if structure / FB definition are augmented - specifically if elements are added - removing elements actually seems to go through without problems. (But thus could also be functional with a non-complicated addition of a similar nature as for the first point - please read below.)
Both issues / real-world situations could be solved or improved on by the possibility of resolving the variable tree down to the actual lowest element level both for reading (and checking if the variable is actually persistent) and writing instead of stopping at the top object/structure level. The second approach could be just by using an absolute "flat" variable structure approach instead of a hierarchical tree approach. Both come down to dealing with individual variable elements.
This could and should be implemented as an on-demand read and write processes, (that is in addition to the existing ones) because the user should be aware and able to chose whether to use the current "hierarchical/object" approach or the "by elements" approach based on what needs to be done. The "by elements" approach could potentially cover all needs, but it probably should not, because it is theoretically a much slower and intensive process for the ADS communication channel.
I suppose this could be implemented on the level of the TwinCatAdsTool, but some supporting functions could be added on the JsonExtension level too - specifically for writing.
Just to see if my argument has any merit I tried a simple brute force addition (as in dirty and quick) to the WriteVariables task in RestoreViewModel.cs, by adding a WriteVariables_Elements (and it's own separate trigger Restore button) so that it resolves the structure futher instead of calling clientService.Client.WriteJson when p.Value is JObject. I know a recursive approach with maximum depth limitation should be used but I just nested some levels of foreach loops to check it out. It works ... this way I can use TwinCadAdsTool to backup variables...change/add to the the structure definition on the PLC and write back the previously stored variable values in case of disaster (which I simulated in this case with a Reset Origin on the PLC).
Something similar could be attempted for the reading side in the ReadPersistentVariables method.
Thinking about it further a "flat" approach might be even better in the end because it could cover other situations too and include arrays with changing index limits, but that might be a further evolution.
Please take this "issue" as a constructive endeavor towards making the Tool even more useful for occasions and purposes where it currently doesn't help and are quite present in real-world - including some Beckhoff's own PLC program implementations.
Best regards.