208 de 208 códigos
La operación requiere privilegios que el proceso no tiene, como cambiar el propietario de un archivo, enviar una señal a un proceso de otro usuario o modificar un archivo inmutable (chattr +i). A diferencia de EACCES, no se resuelve cambiando los permisos del archivo: hace falta root o la capability correspondiente.
El archivo o el directorio no existe. También aparece cuando falta un directorio intermedio de la ruta, cuando un enlace simbólico apunta a un destino que no existe o cuando no está instalado el intérprete de la línea #! de un script.
No existe ningún proceso, grupo de procesos o hilo con ese identificador; por ejemplo, al hacer kill sobre un PID que ya terminó.
Una señal interrumpió la llamada al sistema antes de que terminara. No es un error real: el programa debe reintentar la llamada, o instalar el manejador de la señal con SA_RESTART.
Error de entrada/salida de bajo nivel, en general al leer o escribir en el dispositivo. En discos suele indicar sectores dañados o un cable defectuoso: revisa dmesg y el estado SMART. También aparece al escribir en una terminal que ya se ha cerrado.
El dispositivo o la dirección no existe: el archivo de dispositivo está, pero no hay hardware detrás, o se abrió para escritura un FIFO con O_NONBLOCK sin ningún lector.
La lista de argumentos y variables de entorno que se pasa a exec es demasiado grande. Es el clásico «Argument list too long» al usar un comodín que se expande a miles de archivos; usa find -exec o xargs.
El archivo no tiene un formato ejecutable reconocido: es un binario de otra arquitectura, está dañado o es un script sin línea #!.
El descriptor de archivo no es válido, ya se cerró o se abrió en un modo que no permite la operación, como escribir en uno abierto sólo para lectura.
El proceso no tiene hijos por los que esperar con wait o waitpid, a menudo porque SIGCHLD se ignora y los hijos se recogen solos.
El recurso no está disponible por el momento y conviene reintentar. En operaciones no bloqueantes significa que todavía no hay datos o espacio; en fork, que se alcanzó el límite de procesos o hilos (ulimit -u o pids.max del cgroup).
Mismo valor:EWOULDBLOCK
No hay memoria suficiente para la operación o se superó un límite de memoria del proceso. En fork o mmap puede deberse a la política de overcommit, al límite del cgroup o a la falta de espacio de direcciones.
Permiso denegado por los permisos del archivo o de un directorio de la ruta (hace falta permiso de ejecución en cada uno), por una ACL, por SELinux o AppArmor, o por un montaje con noexec. bind también lo devuelve al usar un puerto menor que 1024 sin privilegios.
Se pasó a una llamada al sistema un puntero a una dirección de memoria no válida. Indica un bug en el programa.
La operación necesita un dispositivo de bloques, como un disco, y recibió otro tipo de archivo; por ejemplo, al montar un archivo común sin -o loop.
El dispositivo o el recurso está en uso. Es típico al desmontar un sistema de archivos que tiene archivos abiertos o una terminal ubicada en él; lsof o fuser muestran qué procesos lo usan.
Ya existe un archivo, un directorio u otro objeto con ese nombre, por ejemplo al crear con O_EXCL, al usar mkdir sin -p o al crear un enlace cuyo destino ya existe.
No se puede crear un enlace duro ni renombrar un archivo entre sistemas de archivos distintos. mv lo resuelve copiando y borrando; los programas que usan rename() deben hacer lo mismo.
El dispositivo no existe o no admite la operación; por ejemplo, al montar un tipo de sistema de archivos cuyo módulo del kernel no está cargado.
Un componente de la ruta que debería ser un directorio es un archivo, o se pidió un directorio (O_DIRECTORY) y no lo es.
Se intentó una operación de archivo sobre un directorio, como abrirlo para escritura.
Un argumento no es válido para la llamada: un valor fuera de rango, una combinación de opciones incompatible o una operación que el objeto no admite. Es genérico: la página man de la llamada lista los casos concretos.
Se agotó la tabla de archivos abiertos de todo el sistema. El límite se ajusta con fs.file-max en sysctl.
El proceso ha alcanzado su límite de descriptores abiertos («Too many open files»). Sube el límite con ulimit -n o con LimitNOFILE en systemd, y revisa que el programa no deje archivos o sockets sin cerrar.
Se pidió una operación de terminal (ioctl) sobre algo que no es una terminal, por ejemplo cuando la salida de un programa interactivo se redirige a un archivo o a un pipe.
El ejecutable está en uso: no se puede escribir en un binario mientras se ejecuta, ni ejecutar uno que sigue abierto para escritura. Para actualizarlo, conviene escribir un archivo nuevo y renombrarlo.
El archivo supera el tamaño máximo que admite el sistema de archivos (4 GB en FAT32) o el límite RLIMIT_FSIZE del proceso.
No queda espacio en el dispositivo. Si df muestra espacio libre, revisa los inodos con df -i. inotify también lo devuelve al agotar fs.inotify.max_user_watches.
No se puede hacer lseek sobre un pipe, un FIFO o un socket, porque no tienen posición.
El sistema de archivos está montado como sólo lectura. Si ha pasado a sólo lectura sin que nadie lo pidiera, ha sido el kernel al detectar errores: revisa dmesg y ejecuta fsck.
Se superó la cantidad máxima de enlaces duros a un archivo, o la de subdirectorios de un directorio en algunos sistemas de archivos.
Se escribió en un pipe o en un socket cuyo otro extremo ya se cerró («Broken pipe»). Además del error, el proceso recibe SIGPIPE; es normal cuando el lector termina antes, como en cmd | head.
El argumento de una función matemática está fuera de su dominio, como la raíz cuadrada de un número negativo.
El resultado de una función es demasiado grande o demasiado pequeño para representarse, o un búfer no basta para el resultado, como en getcwd con un búfer corto.
Se evitó un interbloqueo: el lock pedido, como un bloqueo de archivo con fcntl o un mutex con detección de errores, habría quedado esperando para siempre.
Mismo valor:EDEADLOCK
La ruta o uno de sus componentes supera la longitud máxima: en Linux, en general, 255 bytes por nombre y 4096 por ruta.
No hay locks disponibles. En NFS suele indicar que el servicio de bloqueo (lockd o rpc.statd) no está funcionando.
La llamada al sistema no existe en este kernel o no está implementada. Es típico de binarios compilados para un kernel más nuevo, o de perfiles seccomp de contenedores que no conocen llamadas recientes.
El directorio no está vacío, por ejemplo al usar rmdir o al renombrar sobre un directorio existente. Para borrarlo con su contenido, usa rm -r.
Hay demasiados enlaces simbólicos encadenados al resolver la ruta, normalmente por un ciclo, o se usó O_NOFOLLOW sobre un enlace simbólico.
No hay ningún mensaje del tipo pedido en la cola de mensajes de System V.
El identificador de IPC de System V (cola, semáforo o memoria compartida) se eliminó mientras el proceso lo usaba.
Número de canal fuera de rango. Es un código heredado sin uso práctico en Linux.
Nivel 2 no sincronizado. Es un código heredado de System V sin uso práctico en Linux.
Nivel 3 detenido. Es un código heredado de System V sin uso práctico en Linux.
Nivel 3 reiniciado. Es un código heredado de System V sin uso práctico en Linux.
Número de enlace fuera de rango. Es un código heredado sin uso práctico en Linux.
El controlador del protocolo no está conectado. Lo usan pocos subsistemas, como algunos controladores de Bluetooth.
No hay ninguna estructura CSI disponible. Es un código heredado sin uso práctico en Linux.
Nivel 2 detenido. Es un código heredado de System V sin uso práctico en Linux.
Intercambio no válido. Es un código heredado que algunos controladores y sistemas de archivos reutilizan con un sentido propio.
Descriptor de solicitud no válido. Es un código heredado que algunos controladores reutilizan con un sentido propio.
Intercambio lleno. Es un código heredado sin uso práctico en Linux.
No hay ningún «anode». Es un código heredado sin uso práctico en Linux.
Código de solicitud no válido. Es heredado; algunos controladores lo usan para comandos que no admiten.
Slot no válido. Es un código heredado sin uso práctico en Linux.
Formato de archivo de fuente incorrecto. Es un código heredado sin uso práctico en Linux.
El dispositivo no es un STREAM. Pertenece a la interfaz STREAMS de System V, que Linux no implementa.
No hay datos disponibles. En Linux lo devuelve getxattr cuando el atributo extendido no existe; en macOS ese caso es ENOATTR.
Venció un temporizador. Viene de STREAMS; en Linux lo usan algunos controladores e io_uring para operaciones con tiempo límite.
No quedan recursos de STREAMS, una interfaz que Linux no implementa.
El equipo no está en la red. Es un código heredado de poco uso.
El paquete no está instalado. Es heredado; algunos subsistemas lo usan cuando falta un módulo, por ejemplo uno criptográfico.
El objeto es remoto. En NFS indica una ruta que se exporta desde otro servidor.
Se cortó el enlace. Es heredado; algunos controladores lo usan cuando se pierde la conexión con el dispositivo.
Error de «advertise». Es un código heredado de RFS sin uso en Linux.
Error de «srmount». Es un código heredado de RFS sin uso en Linux.
Error de comunicación al enviar. Es heredado; lo usan algunos controladores de red y USB.
Error de protocolo: el otro extremo o el dispositivo respondió algo inesperado. Aparece con dispositivos USB y en conexiones que se cortan en medio de un intercambio.
Se intentó un salto múltiple (multihop). Es un código heredado de RFS.
Error específico de RFS. Sin uso en Linux.
El mensaje está mal formado o corrupto. ext4, XFS y Btrfs lo devuelven, con el alias EFSBADCRC, cuando falla la suma de verificación de los metadatos.
Mismo valor:EFSBADCRC
El valor no cabe en el tipo de datos de destino; por ejemplo, un programa de 32 bits compilado sin soporte de archivos grandes que abre un archivo de más de 2 GB.
El nombre no es único en la red. Es un código heredado.
El descriptor de archivo está en un estado incorrecto. Lo usan ALSA y algunos controladores cuando el dispositivo no está preparado.
La dirección remota cambió. Es un código heredado.
No se puede acceder a una biblioteca compartida necesaria. Es un código heredado de los binarios a.out.
La biblioteca compartida está dañada. Es un código heredado de los binarios a.out.
La sección .lib del binario a.out está dañada. Es un código heredado.
Se intentó enlazar demasiadas bibliotecas compartidas. Es un código heredado de a.out.
Una biblioteca compartida no se puede ejecutar directamente. Es un código heredado de a.out.
La secuencia de bytes no es válida para la codificación de caracteres, como un texto que no es UTF-8 válido al convertirlo con iconv o con las funciones multibyte.
La llamada interrumpida debe reiniciarse. Es de uso interno del kernel y no debería llegar a los programas.
Error de pipe de STREAMS. ALSA lo devuelve cuando el dispositivo de audio está suspendido.
Hay demasiados usuarios. Lo devuelve el sistema de cuotas de disco cuando se llena su tabla, y es poco común.
Se usó una operación de socket sobre un descriptor que no es un socket.
Falta la dirección de destino: se envió por un socket sin conexión sin indicar adónde.
El mensaje es demasiado grande para el socket, como un datagrama UDP mayor que el máximo o que la MTU cuando no se permite fragmentar.
El protocolo no corresponde al tipo de socket.
La opción de socket o el protocolo pedido no está disponible, por ejemplo una opción de setsockopt que el kernel no conoce.
El protocolo no está soportado, por ejemplo porque su módulo del kernel no está cargado.
El tipo de socket no está soportado en esa familia de direcciones.
La operación no está soportada por el socket o por el objeto. En Linux tiene el mismo valor que ENOTSUP, y muchos sistemas de archivos lo devuelven para funciones que no implementan, como fallocate o los atributos extendidos.
La operación no está soportada. En Linux tiene el mismo valor que EOPNOTSUPP (95); en macOS son códigos distintos.
La familia de protocolos no está soportada.
La familia de direcciones no está soportada; es típico al usar IPv6 en un sistema o un contenedor que lo tiene deshabilitado.
La dirección y el puerto ya están en uso: otro proceso escucha en ese puerto, o la conexión anterior sigue en TIME_WAIT. Busca el proceso con ss -ltnp o lsof -i :PUERTO, o usa SO_REUSEADDR.
No se puede asignar la dirección pedida: la IP no pertenece a ninguna interfaz del equipo, o se agotaron los puertos efímeros para conexiones salientes.
La interfaz de red está caída.
La red de destino es inalcanzable porque no hay ninguna ruta hacia ella. Revisa la tabla de rutas y la puerta de enlace; también pasa al conectar por IPv6 sin conectividad IPv6.
La red reinició la conexión, por ejemplo cuando falla un keepalive.
La conexión se abortó del lado local, por ejemplo porque el cliente la cerró antes de que el servidor la aceptara con accept.
El otro extremo cortó la conexión de golpe con un RST («Connection reset by peer»): el proceso remoto se cerró, un firewall o un balanceador cortó la conexión inactiva, o se enviaron datos que el otro no esperaba.
No hay espacio de búfer disponible en el kernel para la operación de red; suele aparecer con mucho tráfico o con las colas de los sockets llenas.
El socket ya está conectado.
El socket no está conectado: se intentó enviar o recibir antes de conectar, o la conexión ya se cerró. En un montaje FUSE aparece como «Transport endpoint is not connected» cuando su proceso murió; se arregla desmontando con fusermount -u.
No se puede enviar después de cerrar ese sentido del socket con shutdown.
Hay demasiadas referencias; en Linux, al pasar demasiados descriptores anidados por un socket Unix.
Se agotó el tiempo de espera de la conexión porque el destino no respondió. Suele deberse a un firewall que descarta los paquetes en silencio, a un host apagado o a una ruta que no llega.
El destino ha rechazado la conexión: el equipo responde, pero nadie escucha en ese puerto o un firewall responde con un rechazo. Verifica que el servicio esté en ejecución y escuchando en la interfaz correcta, no sólo en 127.0.0.1.
El host de destino está caído.
No hay ruta hacia el host: no responde a ARP en la red local, o un router o un firewall informa que es inalcanzable.
Ya hay una operación en curso sobre el socket, como un connect no bloqueante que todavía no terminó.
La operación está en curso: un connect no bloqueante empezó y terminará más tarde. No es un error; hay que esperar con poll o select.
El identificador de archivo quedó obsoleto: en NFS, el archivo o el directorio se borró o se reemplazó en el servidor. Se soluciona volviendo a abrir la ruta o remontando.
La estructura necesita limpieza: el sistema de archivos ha detectado corrupción (en ext4 y XFS, con el alias EFSCORRUPTED). Desmóntalo y ejecuta fsck o xfs_repair.
Mismo valor:EFSCORRUPTED
No es un archivo con nombre de XENIX. Es un código heredado sin uso.
No hay semáforos de XENIX disponibles. Es un código heredado sin uso.
Es un archivo con nombre de XENIX. Es un código heredado sin uso.
Error de E/S remota, por ejemplo de un dispositivo I2C o de un disco remoto que no respondió.
Se superó la cuota de disco del usuario o del grupo.
No hay ningún medio en el dispositivo, como una unidad óptica sin disco o un lector de tarjetas vacío.
El tipo de medio no es el correcto.
La operación se canceló, por ejemplo una E/S asíncrona o una espera de io_uring.
La clave necesaria no está en el keyring del kernel. Aparece con sistemas de archivos cifrados, como fscrypt o eCryptfs, cuando la clave no se cargó.
La clave expiró. PAM y Kerberos también lo usan cuando caducó la contraseña o el ticket.
La clave fue revocada.
El servicio rechazó la clave.
El propietario de un mutex robusto murió sin liberarlo. El nuevo propietario debe dejar consistente el estado protegido y llamar a pthread_mutex_consistent.
El estado protegido por un mutex robusto no se puede recuperar, porque el propietario anterior murió y nadie lo marcó como consistente.
La operación no es posible porque la radio Wi-Fi o Bluetooth está bloqueada por RF-kill. Revisa rfkill list, el interruptor físico o la tecla de modo avión.
La página de memoria tiene un error de hardware y el kernel la marcó como envenenada.
El tipo de archivo no es el adecuado para la operación. En macOS y BSD existe desde hace mucho; en Linux se ha añadido recientemente.
Hay demasiados procesos. BSD lo define para el límite de procesos, aunque en la práctica fork devuelve EAGAIN.
La estructura de RPC es incorrecta (Sun RPC, que usa NFS).
La versión de RPC no coincide (Sun RPC, que usa NFS).
El programa RPC no está disponible en el servidor.
La versión del programa RPC no coincide.
El procedimiento no existe en el programa RPC.
Error de autenticación, por ejemplo al montar un recurso NFS.
Hace falta un autenticador para la operación.
El dispositivo está apagado.
Error del dispositivo, por ejemplo una impresora sin papel.
El ejecutable no es válido.
El ejecutable es para otro tipo de CPU, como un binario sólo x86_64 en un Mac con Apple Silicon sin Rosetta 2, o uno ARM en un Mac con Intel.
La versión de la biblioteca compartida no coincide.
El archivo Mach-O está mal formado o dañado.
El atributo extendido no existe; equivale al ENODATA de Linux. Aparece con xattr, por ejemplo al quitar com.apple.quarantine de un archivo que no lo tiene.
No hay ninguna política registrada con ese nombre en el MAC Framework.
La cola de salida de la interfaz de red está llena.
Las capacidades no son suficientes: lo devuelven las llamadas que restringe un sandbox.
La terminal que controlaba el proceso se ha cerrado o se ha cortado la sesión SSH. Muchos demonios, como nginx, sshd o rsyslog, la usan como petición para releer la configuración; nohup, tmux y screen evitan que cierre los procesos al salir.
Interrupción desde el teclado con Ctrl+C. El programa puede capturarla para terminar en orden. Código de salida 130.
Salida desde el teclado con Ctrl+\. Termina el proceso con volcado de memoria; la JVM la usa, en cambio, para imprimir el estado de los hilos.
El procesador encontró una instrucción ilegal: un binario compilado para una CPU más nueva (por ejemplo, con AVX2 o AVX-512 en un procesador que no los tiene), código dañado o un salto a datos.
Trampa de depuración: la usan los depuradores para los puntos de interrupción. Si llega sin depurador, suele ser un fallo detectado por el propio programa, como las comprobaciones de Swift en macOS.
El proceso llamó a abort(): una aserción que falló, una excepción de C++ no capturada o una corrupción del heap detectada por la biblioteca de C («double free or corruption»). Código de salida 134.
Mismo valor:SIGIOT
Error de bus: un acceso a memoria mal alineada en algunas arquitecturas, o a una parte de un archivo mapeado con mmap que ya no existe porque el archivo se truncó. También pasa cuando se llena /dev/shm.
Excepción aritmética. A pesar del nombre, la causa más común es una división entera por cero.
Termina el proceso de inmediato: no se puede capturar, bloquear ni ignorar. La envían kill -9, el OOM killer del kernel cuando se agota la memoria, y Docker o Kubernetes cuando un contenedor supera su límite de memoria (OOMKilled) o no termina a tiempo después de SIGTERM. Código de salida 137.
Señal libre para que cada aplicación le dé su propio uso; por ejemplo, dd informa su progreso y nginx reabre los logs.
Violación de segmento («Segmentation fault»): un acceso a memoria no válida, como desreferenciar un puntero nulo, salirse de un array o desbordar la pila con una recursión infinita. Código de salida 139.
Segunda señal libre para que cada aplicación le dé su propio uso.
Escritura en un pipe o un socket sin lector. Es normal en cmd | head, donde el lector termina antes; los servidores suelen ignorarla y manejar el error EPIPE. Código de salida 141.
Venció el temporizador programado con alarm o setitimer.
Petición de terminación ordenada. Es la señal por defecto de kill, systemctl stop, docker stop y de Kubernetes al eliminar un pod; el proceso debería cerrar sus conexiones y salir. Código de salida 143.
Fallo de pila del coprocesador. No se usa en Linux actual.
Un proceso hijo terminó, se detuvo o continuó. El padre debe recogerlo con wait; si no lo hace, el hijo queda como zombi.
Mismo valor:SIGCLD
Reanuda un proceso detenido, como hacen fg y bg en el shell.
Detiene el proceso; no se puede capturar ni ignorar. Se reanuda con SIGCONT.
Detención desde la terminal con Ctrl+Z. A diferencia de SIGSTOP, el programa puede capturarla.
Un proceso en segundo plano intentó leer de la terminal.
Un proceso en segundo plano intentó escribir en la terminal con stty tostop activo, o cambiar su configuración.
Llegaron datos urgentes (fuera de banda) a un socket. Go la usa internamente para interrumpir goroutines.
Se superó el límite de tiempo de CPU del proceso (ulimit -t).
Se superó el tamaño máximo de archivo permitido al proceso (ulimit -f).
Venció el temporizador virtual, que cuenta sólo el tiempo de CPU del proceso.
Venció el temporizador de perfilado, que usan los profilers.
Cambió el tamaño de la ventana de la terminal; los programas de pantalla completa la usan para redibujarse.
Hay E/S disponible en un descriptor configurado con O_ASYNC. En Linux, SIGPOLL es la misma señal.
Mismo valor:SIGPOLL
Fallo de alimentación, que un software de SAI informa al sistema init.
Llamada al sistema incorrecta. Hoy la causa habitual es un filtro seccomp que la bloquea, como en los contenedores.
Trampa de emulación (EMT). Existe en macOS y BSD, pero no en Linux sobre x86 ni ARM.
Petición de información con Ctrl+T en la terminal de macOS y BSD; muchos comandos responden mostrando su progreso.
El comando terminó bien. Es el único código que significa éxito: cualquier otro valor indica un error.
Error general; cada programa decide qué significa. El detalle suele estar en lo que el comando escribió en stderr. grep y diff lo usan con otro sentido: «no encontró coincidencias» o «los archivos son distintos».
Uso incorrecto de un comando interno del shell o error de sintaxis en el script. Muchos programas también lo usan para opciones inválidas, y grep para errores reales.
El comando se usó mal: faltan argumentos, sobran o alguna opción es incorrecta.
Los datos de entrada tienen un formato incorrecto.
Un archivo de entrada no existe o no se puede leer.
El usuario indicado no existe; lo usan sobre todo los programas de correo.
El nombre del host no existe.
Un servicio necesario no está disponible, o falló algo que no encaja en otra categoría.
Error interno del programa.
Error del sistema operativo, como no poder hacer fork o crear un pipe.
Falta un archivo del sistema, como /etc/passwd, o tiene un error.
No se puede crear un archivo de salida.
Error de entrada/salida al leer o escribir un archivo.
Fallo temporal: conviene reintentar más tarde. Los servidores de correo lo usan para dejar el mensaje en la cola.
El sistema remoto respondió algo que no respeta el protocolo.
Permisos insuficientes para la operación.
Hay un error en la configuración.
El comando timeout lo terminó porque superó el tiempo indicado.
Falló el propio docker run antes de ejecutar el contenedor, por ejemplo por una opción incorrecta o un error del daemon. GNU timeout también lo devuelve cuando el que falla es él.
El archivo existe, pero no se puede ejecutar: le falta el permiso de ejecución, es un directorio o es un binario de otra arquitectura. En Docker, el comando del contenedor no es ejecutable.
No se encontró el comando: no está instalado, no está en el PATH o tiene el nombre mal escrito. En scripts también aparece cuando falta el intérprete de la línea #!; en Docker, cuando el comando del contenedor no existe en la imagen.
Los códigos mayores que 128 indican que una señal terminó el proceso, pero 128 no corresponde a ninguna. Git lo usa para todos sus errores fatales («fatal: …»), como un repositorio que no existe o un fallo de autenticación al clonar.
El código de salida quedó fuera de rango: exit -1 llega como 255, porque sólo se conservan 8 bits. ssh también lo devuelve cuando falla la conexión o la autenticación, para distinguirlo del código del comando remoto.
Los valores de Linux son los de x86, x86-64 y ARM; Alpha, MIPS, SPARC y PA-RISC numeran distinto algunos errno y señales. Los mensajes en inglés son los que muestran strerror y strsignal en glibc, y en macOS cuando son distintos. Los códigos de salida mayores que 128 se interpretan como 128 más el número de la señal, que es la convención de bash, Docker y Kubernetes.
Cómo funciona
Cuando una llamada al sistema falla en Linux, devuelve -1 y deja en la variable errno un número que dice por qué: 2 es ENOENT, el archivo no existe; 13 es EACCES, permiso denegado. strerror convierte ese número en el texto que se ve en pantalla, como «No such file or directory». Python lo muestra como [Errno 13], Node.js como code: 'ECONNREFUSED' y Go, Rust o Java con el mismo texto. Los números del 1 al 34 vienen del Unix original y son iguales en todos los sistemas; los siguientes los numeró cada uno a su manera, así que ECONNREFUSED es 111 en Linux y 61 en macOS. El nombre es portable; el número, no.
Las señales son avisos que el kernel u otro proceso le envían a un proceso: SIGINT cuando se pulsa Ctrl+C, SIGTERM para pedirle que termine, SIGKILL para terminarlo sin preguntar, SIGSEGV cuando accede a memoria no válida. Cada una tiene una acción por defecto, y casi todas se pueden capturar para hacer otra cosa. Cuando una señal mata a un proceso, el shell informa como código de salida 128 más el número de la señal: 137 es SIGKILL (9), 139 es SIGSEGV (11) y 143 es SIGTERM (15). Docker y Kubernetes usan la misma convención.
El código de salida es el número que deja un programa al terminar: 0 significa éxito y cualquier otro valor, error. Sólo se conservan 8 bits, así que va de 0 a 255. Hay pocas convenciones: 126 y 127 los usa el shell cuando no puede ejecutar o no encuentra el comando, del 64 al 78 los define sysexits.h de BSD, y el resto lo decide cada programa, como grep, que devuelve 1 cuando no encuentra nada.
Ejemplos
Last State: Terminated · Reason: OOMKilled · Exit Code: 137137 = 128 + 9 · SIGKILLEl contenedor superó su límite de memoria y el kernel lo mató con SIGKILL. Hay que subir el límite en resources.limits.memory o buscar por qué el proceso consume tanto; reiniciarlo no lo arregla.Error: connect ECONNREFUSED 127.0.0.1:5432ECONNREFUSED · Linux 111 · macOS 61 · Connection refusedNode.js no ha podido conectarse a PostgreSQL porque nadie escucha en el puerto 5432. Si la aplicación se ejecuta en un contenedor, 127.0.0.1 es el propio contenedor y no el equipo: hay que usar el nombre del servicio de la base de datos.OSError: [Errno 48] Address already in useEADDRINUSE · Linux 98 · macOS 48El 48 delata que el programa se ejecuta en macOS: en Linux el mismo error es el 98. En ambos casos otro proceso ya usa el puerto; lsof -i :PUERTO muestra cuál.Casos de uso
- Entender un error de una aplicación en Python, Node.js, Go o C que sólo muestra el número o el nombre del errno.
- Averiguar por qué se cerró un contenedor de Docker o se reinicia un pod de Kubernetes a partir de su código de salida.
- Pasar un número de errno de macOS al nombre correcto, que desde el 35 no coincide con el de Linux.
- Interpretar el código de salida de un script, un cron o un job de CI que falló.
- Elegir qué señal enviar con kill y saber qué hace el proceso si no la captura.
- Escribir un manejo de errores portable que compare por nombre en lugar de por número.
Preguntas frecuentes
¿Qué significa el exit code 137?
Que el proceso terminó por la señal 9, SIGKILL (128 + 9). La causa más común es la memoria: el contenedor superó su límite, y Kubernetes lo informa como OOMKilled, o el OOM killer del kernel eligió ese proceso, lo que queda en dmesg como «Out of memory: Killed process». También ocurre con docker kill, o cuando el proceso no termina dentro del plazo después de SIGTERM: 10 segundos en docker stop y 30 en Kubernetes.
¿Qué diferencia hay entre SIGTERM y SIGKILL?
SIGTERM le pide al proceso que termine, y el proceso puede capturarla para cerrar conexiones, guardar datos y salir. SIGKILL lo termina el kernel en el acto, sin que el proceso pueda hacer nada. Lo correcto es enviar SIGTERM, esperar unos segundos y recurrir a SIGKILL sólo si sigue vivo, que es lo que hacen systemd, docker stop y Kubernetes.
¿Por qué el mismo errno tiene otro número en macOS?
Porque POSIX define los nombres pero no los números. Del 1 al 34 todos los sistemas heredaron los del Unix original; después, BSD, del que viene macOS, y System V, que siguió Linux, los numeraron por separado. Por eso conviene comparar siempre por nombre, con errno.ECONNREFUSED en Python, err.code en Node.js o la constante en C, y no con el número.
¿Qué diferencia hay entre EACCES y EPERM?
EACCES («Permission denied») significa que los permisos del archivo o de algún directorio de la ruta no lo permiten, o lo impide una ACL o SELinux: se resuelve con chmod, chown o la política correspondiente. EPERM («Operation not permitted») significa que la operación en sí requiere privilegios, sin importar los permisos, como cambiar el propietario de un archivo o matar un proceso de otro usuario: hace falta root, una capability o quitar un atributo como el de inmutable.
¿Cómo veo el código de salida de un comando o un contenedor?
En bash y zsh, echo $? muestra el del último comando; en PowerShell, $LASTEXITCODE. En Docker, docker ps -a lo muestra en la columna STATUS, como «Exited (137)». En Kubernetes, kubectl describe pod lo muestra en «Last State: Terminated», junto con el motivo, como OOMKilled o Error.