Errores como Valores: La Filosofía de Errores de Go
Go rechaza las excepciones para las rutas de fallo esperadas.
Busca en todas las páginas de la documentación
Go rechaza las excepciones para las rutas de fallo esperadas.
En su lugar, las funciones devuelven un valor error junto a su resultado normal, y los llamadores deciden inmediatamente si propagar, encapsular, registrar o traducir ese fallo.
Esa elección moldea la legibilidad, los límites de las bibliotecas y cómo los servicios de producción mapean los problemas del dominio a respuestas HTTP o gRPC.
error devuelto como cualquier otro resultado - no un mecanismo de control de flujo que desenrolla la pila.catch ocultos.error, errores centinela, encapsulamiento con %w, errors.Is / errors.As, panic vs error, fallo rápido en los límites.if err != nil añaden verbosidad; las pilas de llamadas profundas requieren un encapsulamiento disciplinado; no hay reintentos o clasificación integrados a menos que tú los diseñes.Antes de Go 1, los diseñadores observaron que las bases de código C++ y Java luchaban con excepciones utilizadas tanto para fallos esperados como catastróficos.
El flujo de control oculto hacía difícil saber qué funciones podían fallar, y los bloques catch lejanos a la causa oscurecían la remediación.
La respuesta de Go es la simplicidad mecánica: una firma de función te dice todo.
func ReadConfig(path string) (Config, error)Si el segundo retorno no es nil, el primer valor suele ser inutilizable.
No hay try, ni finally, ni desenrollado implícito de pila para problemas ordinarios.
La interfaz error es intencionalmente diminuta:
type error interface {
Error() string
}Cualquier cosa con un método string la satisface: variables centinela, mensajes formateados, estructuras ricas con campos adicionales.
Los errores como valores significa que los pasas como int o string: los almacenas, los comparas con errors.Is, inspeccionas tipos con errors.As, y adjuntas contexto con fmt.Errorf("load config: %w", err).
Panic existe, pero Go idiomático lo reserva para violaciones de invariantes y errores de programador (desreferencia de puntero nil, índice fuera de rango).
Las bibliotecas no deben entrar en pánico ante una entrada de usuario incorrecta; las aplicaciones pueden optar por fallar al inicio si la configuración es incorrecta.
El modelo de errores interactúa con otras opciones explícitas de Go: valores de retorno múltiples, sin herencia y API a nivel de paquete.
Un paquete de bajo nivel como os exporta errores centinela (os.ErrNotExist) y encapsuladores específicos de la operación.
Middleware y manejadores se sientan en los límites - manejadores HTTP, interceptores gRPC, CLI main - donde los errores se convierten en códigos de estado, códigos de salida o campos de registro estructurados.
Entre esas capas, el código generalmente encapsula errores para añadir contexto mientras preserva la causa raíz para errors.Is y errors.As.
llamador ──llama──> biblioteca ──devuelve──> (T, error)
│ │
│ si err != nil │
├─ encapsular con %w ───────────────────┘
├─ registrar + devolver
└─ mapear a respuesta del cliente en el límite
El encapsulamiento (Go 1.13+) almacena una cadena de desenrollado.
errors.Is(err, target) recorre esa cadena para la igualdad de centinelas.
errors.As(err, &target) encuentra el primer valor de error asignable a un tipo puntero.
Esto reemplaza la comparación frágil de cadenas y las aserciones de tipo en cada capa.
Las bibliotecas deben devolver errores estables y documentados; las aplicaciones no deben filtrar errores os crudos a clientes externos sin traducción.
El paquete context añade cancelación (context.Canceled, context.DeadlineExceeded) como errores de primera clase que se propagan a través del mismo patrón (T, error).
A escala, los equipos adoptan políticas de errores: convenciones de nomenclatura (Err prefijo para centinelas), si exportar tipos de error y cuándo usar %w vs %v (encapsular vs reemplazar cadena).
| Enfoque | Fortaleza | Debilidad | Mejor Ajuste |
|---|---|---|---|
Centinela var ErrX = errors.New(...) | Comprobaciones simples de errors.Is | Se vuelve difícil de manejar con muchas variantes | Vocabularios de dominio pequeños |
| Tipos de estructura personalizados | Campos ricos (código HTTP, reintentable) | Los llamadores deben usar errors.As | Límites de servicio, SDKs |
Errores opacos + Unwrap | API pública estable | Menos inspeccionable para los llamadores | Bibliotecas públicas |
panic + recover | Detiene el goroutine ante rotura de invariante | Fácil de malinterpretar en los bordes de la API | Middleware HTTP, motores de plantillas |
Los ganchos de observabilidad a menudo residen en tipos personalizados: Retryable() bool, LogLevel() slog.Level, o detalles de status gRPC.
Go 1.20+ errors.Join fusiona múltiples fallos (útil en validación y fan-in paralelo).
Para código concurrente, los errores todavía se devuelven en canales o a través de errgroup; la filosofía de valores no cambia, solo la ruta de agregación.
Seguridad: encapsular la entrada del usuario en cadenas de error puede filtrar detalles internos; mapear a mensajes de cliente seguros en la capa más externa.
err es un error, y los linters marcan los errores no comprobados.if err != nil significa que el manejo de errores de Go es débil - La verbosidad proporciona razonamiento local; el encapsulamiento y errors.Is/As proporcionan inspección estructurada sin una jerarquía de excepciones paralela.error para que las herramientas CLI, los servidores y las pruebas puedan recuperarse o informar limpiamente.err == io.EOF siempre funciona - Los errores encapsulados fallan la igualdad directa; usa errors.Is(err, io.EOF).%w - Usa %v cuando la causa interna no deba ser visible para Is/As (límites de seguridad o abstracción).Una interfaz de un solo método (Error() string). Los tipos concretos la implementan para representar un fallo sin una jerarquía de clases.
Querían que el fallo fuera visible en las firmas de las funciones y se manejara localmente, evitando el flujo de control oculto y los bloques catch distantes que oscurecen el flujo de datos en bases de código grandes.
Solo cuando la operación tuvo éxito. Nunca devuelvas un puntero nil tipado como un valor de interfaz error - usa var err error o devuelve un nil sin tipo.
Superficialmente, pero Go idiomático limita panic a errores irrecuperables del programador. Los fallos esperados usan el retorno error.
fmt.Errorf("contexto: %w", err) añade un mensaje y preserva la cadena para errors.Is y errors.As. Los llamadores pueden hacer coincidir centinelas o tipos a través de los encapsulamientos.
Exporta un conjunto pequeño y estable. Prefiere centinelas documentados o tipos para errores de contrato; mantén los detalles internos sin exportar u opacos.
A menudo una vez en el límite (manejador HTTP, bucle de trabajador) después de encapsular upstream. Registrar en cada capa duplica el ruido a menos que cada capa añada contexto distinto.
context.Context devuelve context.Canceled o context.DeadlineExceeded. Propaga con %w para que los llamadores distingan el tiempo de espera del fallo de I/O.
Evítalo. Usa errors.Is para casos esperados (por ejemplo, io.EOF), no para ramificaciones rutinarias a través de muchas capas.
errors.Join (Go 1.20+) agrega múltiples errores en un solo valor que se desenrolla a cada constituyente. Útil cuando varias validaciones fallan en paralelo.
La asignación de valores de error tiene un costo pequeño. Las rutas críticas a veces usan retornos centinela sin formato, pero la claridad generalmente supera las micro-optimizaciones a menos que los perfiles demuestren lo contrario.
Las capas de dominio devuelven error; las capas de transporte las mapean a códigos de estado y cuerpos JSON estables. Consulta el artículo de diseño de errores de API para patrones concretos.
Versiones de Pila: Esta página fue escrita para Go 1.26.x (predeterminado Green Tea GC, go fix modernizers - verificar parche en la compilación), chi (última - verificar en la compilación), gin (última - verificar en la compilación), echo (última - verificar en la compilación), google.golang.org/grpc (última - verificar en la compilación), sigs.k8s.io/controller-runtime (última - verificar en la compilación), kubebuilder (última - verificar en la compilación), tinygo (última - verificar objetivos de placa en la compilación), wazero (última - verificar en la compilación), y golangci-lint (última - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 16 jul 2026