This is the critical point. Are there good uses of the GOTO? Maybe. But when I have this discussion with programming students, who always want to argue the case, none of their presented arguments are of the “good uses” variety (e.g. see example presented in OP). Most students, to be honest, seem to just want to use gotos because they’ve been told they shouldn’t. The good/bad use doesn’t really factor in except as an excuse.
So it’s easier to forbid them altogether to students. I can’t think of a case in which removing a goto results in significantly harder to understand code, so I’m not penalizing them adversely. If a programmer later in life comes across a case where it’s better, they at least have the knowledge of the other options, and can make an informed decision.
A number of software engineering books seem to consider the “goto end on error” metaphor–when there are several jumps to the label in the routine from rare conditions, not like the OP-- to be an (the sole?) acceptable use of a GOTO.
Even that support seems to be eroding, though, in languages which support structured exception handling (Java, anything.NET, C++, several others).
A “try block” around the code with the potential errors, with the GOTO’s replaced by “throws”, gives you code of roughly the same size, plus the ability to handle the exception at another level entirely, plus the ability to write consistent exception handling throughout the application (you could call a function to report the caught error, for example), plus a method whose actual NAME implies you’re handling exceptions, plus debugging support on the throw and catch, plus automatic stack unwinds (and object destructors called in C++)…
Of course, not all languages have exception handling. In that case, the GOTO may still be the clean solution. That having been said, it’s been decades since I used one in any language - the alternatives are just never all that bad.