Yeah, I'm brand new to learning Go, but that was the first thing I thought when I got to his section on errors. You're supposed to return a generalized error and then use errors.is or errors.as to figure out what specific type of error it is so that you can access the specific data on it. And the reason you do it that way instead of just returning a concrete error type is because one function might want to return different error types depending on what specific thing happened. Just like you can throw different exception types in other languages. And obviously if that's happening, the reason you can't just directly access stuff without doing errors.is or as is because you don't know which it is until you do that.
I think it's a shame that Go doesn't have sum types, exhaustiveness checking, and pattern matching, because it would make its error model more enforceable and concise (see Gleam!) but given that it doesn't for whatever reason, I think the solution it's gone with is genuinely the best possible second option that gives you 90% of the benefits of result and option (out of band errors, structured error data, errors as values so you can directly and in line decide what to do with them without special control flow, no invisible or non-local control flow, it's immediately obvious when anything can return an error, etc).
And I say this as someone who started out hating go.