I mean, yeah, if your language does not support error values, do not use them.
Nonsense. If adopting info of the many libraries already available is not for you, it's trivial to roll your own result type.
Even if that was somehow unexplainably not an option, even the laziest of developers can write a function to return a std::tuple or a std::pair and use structured binding.
Zero protections against what? Against the programmer telling the program to do something it shouldn't? Not programming language does that. If you resort to this sort of convoluted reasoning, the same hypothetical programmer can also swallow all exceptions.
The main problem you're creating for yourself is that you've been given an open-ended problem but instead prefer to not look for solutions.