Anything but the last one. Don’t duplicate the http code in the body, else you’re now maintaining something you don’t need to maintain.
I’m not a fan of codes that repeat information in the body either, but I think if you had used a different example like “INVALID_BLAH” or something then the message covered what was invalid, then it would be fine. Like someone else said, the error data should be in an object as well, so that you don’t have to use polymorphism to figure out whether it’s an error or not. That also allows partially complete responses, e.g. data returns, along with an error.
when the official docs are telling you to use it, then it’s used. You can have no expectation of people to think the tooling isn’t shit when it’s literally the official recommendation.