Envoltura de Errores con %w y errors.As
La envoltura añade contexto a los fallos mientras preserva la causa original para su inspección.
Busca en todas las páginas de la documentación
La envoltura añade contexto a los fallos mientras preserva la causa original para su inspección.
fmt.Errorf con %w construye una cadena de desenvoltura; errors.Is y errors.As recorren esa cadena para que los llamadores reconozcan centinelas y tipos personalizados a través de capas intermedias.
Go 1.13 estandarizó la envoltura de errores: cada capa añade contexto de operación (leer configuración, conectar a db) sin destruir el os.ErrNotExist raíz o tu tipo de dominio.
errors.As extrae datos tipados cuando un centinela es demasiado genérico.
Usa %v cuando el error interno no deba participar en Is/As.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
if err != nil {
return fmt.Errorf("obtener usuario %q: %w", id, err)
}
var pathErr *os.PathError
if errors.As(err, &pathErr) {
log.Println("ruta:", pathErr.Path)
}
if errors.Is(err, os.ErrNotExist) {
return ErrNotFound
}Cuándo usar esto:
errors.Joinpackage main
import (
"errors"
"fmt"
"net"
"os"
)
type OpError struct {
Op string
}
func (e OpError) Error() string {
return fmt.Sprintf("%s falló", e.Op)
}
func readDB(path string) error {
_, err := os.ReadFile(path)
if err != nil {
return OpError{Op: "leer"}
}
return nil
}
func loadUser(path string) error {
if err := readDB(path); err != nil {
return fmt.Errorf("cargar usuario desde %q: %w", path, err)
}
return nil
}
func main() {
err := loadUser("missing.db")
var op OpError
if errors.As(err, &op) {
fmt.Println("operación:", op.Op)
}
fmt.Println("no existe:", errors.Is(err, os.ErrNotExist))
fmt.Println("tiempo de espera de red:", errors.Is(err, net.ErrClosed))
}Lo que esto demuestra:
OpError es alcanzable a través de una envoltura fmt.Errorferrors.As requiere un puntero al tipo de destinoerrors.Is todavía encuentra os.ErrNotExist bajo OpError si la cadena lo incluyeIs/As son para lógica de programa%w crea un envoltorio que implementa Unwrap() error.errors.Unwrap(err) devuelve un nivel; Is/As iteran hasta encontrar una coincidencia o nil.%w por llamada a fmt.Errorf.errors.Join(errs...) (Go 1.20+) devuelve un error que se desenvuelve en múltiples valores; Is/As comprueban cada uno.| Verbo | Cadena de desenvoltura | errors.Is / errors.As |
|---|---|---|
%w | Preserva el interior | Funciona a través de la envoltura |
%v | Sin enlace de desenvoltura | El interior no es visible para Is/As |
error o un puntero a un campo de struct.true y asigna el primer valor coincidente en la cadena.// Extracción tipada
var pe *os.PathError
if errors.As(err, &pe) {
_ = pe.Path
}
// Desenvoltura manual de un nivel (raro)
inner := errors.Unwrap(err)%w en un Errorf - Error de compilación. Solución: Envuelve una vez por llamada; encadena con fmt.Errorf anidado.var target MyErr; errors.As(err, &target).errors.As en *MyErr vs MyErr debe coincidir con lo que devuelves. Solución: Sé consistente; documenta el tipo de retorno del constructor.errors.Is es más simple para var ErrX. Solución: Reserva As para tipos con campos.%w junto con logs verbosos pueden exponer tokens. Solución: Sanea los mensajes; usa %v en los límites públicos.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
Solo errors.Is | La identidad del centinela es suficiente | Necesitas campos estructurados |
| Errores planos sin envoltura | Herramienta CLI de una sola capa | Servicios multi-paquete que necesitan cadenas de causa |
status.Convert (gRPC) | Mapeo de transporte RPC | Capa de dominio pura |
Unwrap []error personalizado | Agregación de múltiples errores | Rutas simples de fallo único |
Envuelve el argumento de error para que el resultado implemente Unwrap y participe en errors.Is y errors.As.
errors.As recorre la cadena de desenvoltura. Una aserción de tipo solo inspecciona el tipo dinámico de nivel superior.
fmt.Errorf("msg: %w", nil) produce un error con desenvoltura nil. Evita envolver; devuelve nil en rutas de éxito.
No hay un límite estricto, pero las cadenas profundas sugieren falta de logging en los límites. Prefiere el contexto en capas significativas.
Sí. Haz coincidir la forma del puntero que devuelves (*MyErr) y pasa &target del tipo correcto a As.
Cuando varias operaciones fallan en paralelo (validación, fan-in) y quieres un único error devuelto que liste todas las causas.
Acceso de bajo nivel al error interno inmediato. La mayoría del código usa Is/As en lugar de bucles manuales.
Sí, añade contexto en el límite de tu API (paquete x: operación fallida). No registres y envuelvas redundantemente sin nueva información.
Implementa Unwrap() error en tu tipo o usa fmt.Errorf con %w para un comportamiento estándar.
Ayudantes como os.IsNotExist usan errors.Is internamente, por lo que funcionan a través de cadenas %w que contienen os.ErrNotExist.
Usa Is para centinelas que se mapean a códigos de estado; As al extraer detalles del error para respuestas JSON estructuradas.
Pequeño costo de asignación por envoltura. La claridad y la capacidad de depuración suelen dominar a menos que el profiling muestre un problema en una ruta crítica.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado de GC Green Tea, go fix modernizers - verificar parche en la compilación), chi (última versión - verificar en la compilación), gin (última versión - verificar en la compilación), echo (última versión - verificar en la compilación), google.golang.org/grpc (última versión - verificar en la compilación), sigs.k8s.io/controller-runtime (última versión - verificar en la compilación), kubebuilder (última versión - verificar en la compilación), tinygo (última versión - verificar objetivos de placa en la compilación), wazero (última versión - verificar en la compilación), y golangci-lint (última versión - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 16 jul 2026