You've managed to miss the entire point of using a union: the value is either a success payload or an error value, never both.
You can't encode that mutual exclusivity if you return a std::pair or std::tuple. That's exactly why std::expected, std::variant, or Rust enums exist, to make that constraint explicit in the type system.
Yeah that makes sense. My assertion was definitely incorrect, but also not really what I was trying to describe. My argument is that they are not conceptually different. The implementation is different, in that a union occupies the same memory for either value, but whether they occupy the same memory or not, you have to check the value to determine that is an error. The compiler can force you to handle multiple return values the same way it can force you to check a variant.