Передавать ошибки через канал в основную горутину или использовать errgroup. Не полагаться на панику - перехватывать и превращать в ошибку или передавать в канал. Результат и ошибку можно вернуть через один канал структур.
type result struct { v int; err error }
ch := make(chan result, 1)
go func() { v, err := do(); ch <- result{v, err} }()
r := <-ch