It's pretty much the only approach to do what you want. net/http, for example, just catches panics in each goroutine that it spawns, and logs those, but doesn't attempt to fan those into the main goroutine. Note that if you don't generate a stack trace in the goroutine from which the panic occurred, then the best you can do is get a stack dump of all goroutines; if the recovered-panic goroutine terminates after passing the error to main, but before main can generate the "all goroutines" stack trace, then the panicked goroutine will not be included in that output; since error values don't implicitly contain stack trace information, at that point, you'd have an error with absolutely no context (assuming that an error was even passed to the panic call), which means it'd be virtually worthless for debugging purposes, unless you explicitly stuff a stack trace into the error that you pass on to main.
Go's approach to panics is that they be used only for truly exceptional problems (such as divide by zero errors, array bounds violations, or clear misuse of an API by the application programmer); the accepted approach when this happens is to have the panic either kill the program, or at least be logged quite loudly, so that the problem can be fixed -- panics shouldn't be considered to be part of the normal operation of a correctly written/functioning program.