208 di 208 codici
L'operazione richiede privilegi che il processo non ha, come cambiare il proprietario di un file, inviare un segnale a un processo di un altro utente o modificare un file immutabile (chattr +i). A differenza di EACCES, non si risolve cambiando i permessi del file: servono root o la capability corrispondente.
Il file o la directory non esiste. Compare anche quando manca una directory intermedia del percorso, quando un link simbolico punta a una destinazione che non esiste o quando non è installato l'interprete della riga #! di uno script.
Non esiste alcun processo, gruppo di processi o thread con quell'identificatore; per esempio, quando si esegue kill su un PID già terminato.
Un segnale ha interrotto la chiamata di sistema prima che terminasse. Non è un vero errore: il programma deve ritentare la chiamata o installare il gestore del segnale con SA_RESTART.
Errore di input/output di basso livello, in genere durante la lettura o la scrittura sul dispositivo. Sui dischi indica di solito settori danneggiati o un cavo difettoso: controlla dmesg e lo stato SMART. Compare anche quando si scrive su un terminale già chiuso.
Il dispositivo o l'indirizzo non esiste: il file di dispositivo c'è, ma dietro non c'è alcun hardware, oppure è stata aperta in scrittura una FIFO con O_NONBLOCK senza alcun lettore.
L'elenco di argomenti e variabili d'ambiente passato a exec è troppo grande. È il classico «Argument list too long» quando si usa un carattere jolly che si espande in migliaia di file; usa find -exec o xargs.
Il file non ha un formato eseguibile riconosciuto: è un binario di un'altra architettura, è danneggiato o è uno script senza riga #!.
Il descrittore di file non è valido, è già stato chiuso o è stato aperto in una modalità che non consente l'operazione, come scrivere su uno aperto in sola lettura.
Il processo non ha figli da attendere con wait o waitpid, spesso perché SIGCHLD viene ignorato e i figli vengono raccolti automaticamente.
La risorsa non è disponibile al momento ed è meglio riprovare. Nelle operazioni non bloccanti significa che non ci sono ancora dati o spazio; in fork, che è stato raggiunto il limite di processi o thread (ulimit -u o pids.max del cgroup).
Stesso valore:EWOULDBLOCK
Non c'è memoria sufficiente per l'operazione o è stato superato un limite di memoria del processo. In fork o mmap può dipendere dalla politica di overcommit, dal limite del cgroup o dalla mancanza di spazio di indirizzamento.
Permesso negato dai permessi del file o di una directory del percorso (serve il permesso di esecuzione su ciascuna), da un'ACL, da SELinux o AppArmor, o da un mount con noexec. Anche bind lo restituisce quando si usa una porta inferiore a 1024 senza privilegi.
È stato passato a una chiamata di sistema un puntatore a un indirizzo di memoria non valido. Indica un bug nel programma.
L'operazione richiede un dispositivo a blocchi, come un disco, e ha ricevuto un altro tipo di file; per esempio, quando si monta un file normale senza -o loop.
Il dispositivo o la risorsa è in uso. È tipico quando si smonta un file system che ha file aperti o un terminale posizionato al suo interno; lsof o fuser mostrano quali processi lo usano.
Esiste già un file, una directory o un altro oggetto con quel nome, per esempio quando si crea con O_EXCL, si usa mkdir senza -p o si crea un link la cui destinazione esiste già.
Non si può creare un hard link né rinominare un file tra file system diversi. mv lo risolve copiando ed eliminando; i programmi che usano rename() devono fare lo stesso.
Il dispositivo non esiste o non supporta l'operazione; per esempio, quando si monta un tipo di file system il cui modulo del kernel non è caricato.
Un componente del percorso che dovrebbe essere una directory è un file, oppure è stata richiesta una directory (O_DIRECTORY) e non lo è.
È stata tentata un'operazione su file su una directory, come aprirla in scrittura.
Un argomento non è valido per la chiamata: un valore fuori intervallo, una combinazione di opzioni incompatibile o un'operazione che l'oggetto non supporta. È generico: la pagina man della chiamata elenca i casi concreti.
La tabella dei file aperti dell'intero sistema è esaurita. Il limite si regola con fs.file-max in sysctl.
Il processo ha raggiunto il suo limite di descrittori aperti («Too many open files»). Alza il limite con ulimit -n o con LimitNOFILE in systemd, e controlla che il programma non lasci file o socket aperti.
È stata richiesta un'operazione di terminale (ioctl) su qualcosa che non è un terminale, per esempio quando l'output di un programma interattivo viene reindirizzato a un file o a una pipe.
L'eseguibile è in uso: non si può scrivere in un binario mentre è in esecuzione, né eseguirne uno ancora aperto in scrittura. Per aggiornarlo, conviene scrivere un nuovo file e rinominarlo.
Il file supera la dimensione massima supportata dal file system (4 GB in FAT32) o il limite RLIMIT_FSIZE del processo.
Non c'è più spazio sul dispositivo. Se df mostra spazio libero, controlla gli inode con df -i. Anche inotify lo restituisce quando si esaurisce fs.inotify.max_user_watches.
Non si può eseguire lseek su una pipe, una FIFO o un socket, perché non hanno una posizione.
Il file system è montato in sola lettura. Se è passato in sola lettura senza che nessuno lo chiedesse, è stato il kernel dopo aver rilevato errori: controlla dmesg ed esegui fsck.
È stato superato il numero massimo di hard link a un file o, in alcuni file system, quello di sottodirectory di una directory.
Si è scritto su una pipe o su un socket la cui altra estremità è già stata chiusa («Broken pipe»). Oltre all'errore, il processo riceve SIGPIPE; è normale quando il lettore termina prima, come in cmd | head.
L'argomento di una funzione matematica è fuori dal suo dominio, come la radice quadrata di un numero negativo.
Il risultato di una funzione è troppo grande o troppo piccolo per essere rappresentato, oppure un buffer non basta per il risultato, come in getcwd con un buffer corto.
È stato evitato un deadlock: il lock richiesto, come un lock su file con fcntl o un mutex con rilevamento degli errori, sarebbe rimasto in attesa per sempre.
Stesso valore:EDEADLOCK
Il percorso o uno dei suoi componenti supera la lunghezza massima: in Linux, in genere, 255 byte per nome e 4096 per percorso.
Non ci sono lock disponibili. Su NFS indica di solito che il servizio di locking (lockd o rpc.statd) non è in funzione.
La chiamata di sistema non esiste in questo kernel o non è implementata. È tipico dei binari compilati per un kernel più recente o dei profili seccomp dei container che non conoscono le chiamate recenti.
La directory non è vuota, per esempio quando si usa rmdir o si rinomina sopra una directory esistente. Per eliminarla con il suo contenuto, usa rm -r.
Ci sono troppi link simbolici concatenati nella risoluzione del percorso, di solito per un ciclo, oppure è stato usato O_NOFOLLOW su un link simbolico.
Non c'è alcun messaggio del tipo richiesto nella coda di messaggi System V.
L'identificatore IPC System V (coda, semaforo o memoria condivisa) è stato rimosso mentre il processo lo usava.
Numero di canale fuori intervallo. È un codice storico senza uso pratico in Linux.
Livello 2 non sincronizzato. È un codice storico di System V senza uso pratico in Linux.
Livello 3 arrestato. È un codice storico di System V senza uso pratico in Linux.
Livello 3 reimpostato. È un codice storico di System V senza uso pratico in Linux.
Numero di link fuori intervallo. È un codice storico senza uso pratico in Linux.
Il driver del protocollo non è collegato. Lo usano pochi sottosistemi, come alcuni driver Bluetooth.
Nessuna struttura CSI disponibile. È un codice storico senza uso pratico in Linux.
Livello 2 arrestato. È un codice storico di System V senza uso pratico in Linux.
Scambio non valido. È un codice storico che alcuni driver e file system riutilizzano con un significato proprio.
Descrittore di richiesta non valido. È un codice storico che alcuni driver riutilizzano con un significato proprio.
Scambio pieno. È un codice storico senza uso pratico in Linux.
Nessun «anode». È un codice storico senza uso pratico in Linux.
Codice di richiesta non valido. È storico; alcuni driver lo usano per i comandi che non supportano.
Slot non valido. È un codice storico senza uso pratico in Linux.
Formato di file di font non corretto. È un codice storico senza uso pratico in Linux.
Il dispositivo non è uno STREAM. Appartiene all'interfaccia STREAMS di System V, che Linux non implementa.
Nessun dato disponibile. In Linux lo restituisce getxattr quando l'attributo esteso non esiste; in macOS questo caso è ENOATTR.
Un timer è scaduto. Proviene da STREAMS; in Linux lo usano alcuni driver e io_uring per le operazioni con timeout.
Non restano risorse STREAMS, un'interfaccia che Linux non implementa.
La macchina non è in rete. È un codice storico poco usato.
Il pacchetto non è installato. È storico; alcuni sottosistemi lo usano quando manca un modulo, per esempio uno crittografico.
L'oggetto è remoto. In NFS indica un percorso esportato da un altro server.
Il collegamento è stato interrotto. È storico; alcuni driver lo usano quando si perde la connessione con il dispositivo.
Errore di «advertise». È un codice storico di RFS senza uso in Linux.
Errore di «srmount». È un codice storico di RFS senza uso in Linux.
Errore di comunicazione durante l'invio. È storico; lo usano alcuni driver di rete e USB.
Errore di protocollo: l'altra estremità o il dispositivo ha risposto qualcosa di inatteso. Compare con i dispositivi USB e nelle connessioni che si interrompono a metà di uno scambio.
È stato tentato un salto multiplo (multihop). È un codice storico di RFS.
Errore specifico di RFS. Senza uso in Linux.
Il messaggio è malformato o corrotto. ext4, XFS e Btrfs lo restituiscono, con l'alias EFSBADCRC, quando fallisce il checksum dei metadati.
Stesso valore:EFSBADCRC
Il valore non entra nel tipo di dati di destinazione; per esempio, un programma a 32 bit compilato senza supporto per i file di grandi dimensioni che apre un file di oltre 2 GB.
Il nome non è univoco sulla rete. È un codice storico.
Il descrittore di file è in uno stato non corretto. Lo usano ALSA e alcuni driver quando il dispositivo non è pronto.
L'indirizzo remoto è cambiato. È un codice storico.
Impossibile accedere a una libreria condivisa necessaria. È un codice storico dei binari a.out.
La libreria condivisa è danneggiata. È un codice storico dei binari a.out.
La sezione .lib del binario a.out è danneggiata. È un codice storico.
Si è tentato di collegare troppe librerie condivise. È un codice storico di a.out.
Una libreria condivisa non può essere eseguita direttamente. È un codice storico di a.out.
La sequenza di byte non è valida per la codifica dei caratteri, come un testo che non è UTF-8 valido quando lo si converte con iconv o con le funzioni multibyte.
La chiamata interrotta deve essere riavviata. È di uso interno del kernel e non dovrebbe arrivare ai programmi.
Errore di pipe di STREAMS. ALSA lo restituisce quando il dispositivo audio è sospeso.
Ci sono troppi utenti. Lo restituisce il sistema delle quote disco quando la sua tabella si riempie, ed è poco comune.
È stata usata un'operazione su socket su un descrittore che non è un socket.
Manca l'indirizzo di destinazione: si è inviato tramite un socket senza connessione senza indicare dove.
Il messaggio è troppo grande per il socket, come un datagramma UDP più grande del massimo o della MTU quando la frammentazione non è consentita.
Il protocollo non corrisponde al tipo di socket.
L'opzione di socket o il protocollo richiesto non è disponibile, per esempio un'opzione di setsockopt che il kernel non conosce.
Il protocollo non è supportato, per esempio perché il suo modulo del kernel non è caricato.
Il tipo di socket non è supportato in questa famiglia di indirizzi.
L'operazione non è supportata dal socket o dall'oggetto. In Linux ha lo stesso valore di ENOTSUP, e molti file system lo restituiscono per le funzioni che non implementano, come fallocate o gli attributi estesi.
L'operazione non è supportata. In Linux ha lo stesso valore di EOPNOTSUPP (95); in macOS sono codici distinti.
La famiglia di protocolli non è supportata.
La famiglia di indirizzi non è supportata; è tipico quando si usa IPv6 su un sistema o un container in cui è disabilitato.
L'indirizzo e la porta sono già in uso: un altro processo è in ascolto su quella porta, oppure la connessione precedente è ancora in TIME_WAIT. Trova il processo con ss -ltnp o lsof -i :PORTA, oppure usa SO_REUSEADDR.
Impossibile assegnare l'indirizzo richiesto: l'IP non appartiene a nessuna interfaccia della macchina, oppure sono esaurite le porte effimere per le connessioni in uscita.
L'interfaccia di rete non è attiva.
La rete di destinazione è irraggiungibile perché non esiste alcuna route verso di essa. Controlla la tabella di routing e il gateway; succede anche quando ci si connette tramite IPv6 senza connettività IPv6.
La rete ha reimpostato la connessione, per esempio quando fallisce un keepalive.
La connessione è stata interrotta sul lato locale, per esempio perché il client l'ha chiusa prima che il server la accettasse con accept.
L'altra estremità ha chiuso bruscamente la connessione con un RST («Connection reset by peer»): il processo remoto si è chiuso, un firewall o un bilanciatore di carico ha interrotto la connessione inattiva, oppure sono stati inviati dati che l'altra parte non si aspettava.
Non c'è spazio di buffer disponibile nel kernel per l'operazione di rete; di solito compare con molto traffico o con le code dei socket piene.
Il socket è già connesso.
Il socket non è connesso: si è tentato di inviare o ricevere prima di connettersi, oppure la connessione è già stata chiusa. In un mount FUSE compare come «Transport endpoint is not connected» quando il suo processo è terminato; si risolve smontando con fusermount -u.
Impossibile inviare dopo aver chiuso quella direzione del socket con shutdown.
Ci sono troppi riferimenti; in Linux, quando si passano troppi descrittori annidati tramite un socket Unix.
Il tempo di attesa della connessione è scaduto perché la destinazione non ha risposto. Di solito dipende da un firewall che scarta i pacchetti in silenzio, da un host spento o da una route che non arriva a destinazione.
La destinazione ha rifiutato la connessione: la macchina risponde, ma nessuno è in ascolto su quella porta oppure un firewall risponde con un rifiuto. Verifica che il servizio sia in esecuzione e in ascolto sull'interfaccia corretta, non solo su 127.0.0.1.
L'host di destinazione non è attivo.
Non c'è alcuna route verso l'host: non risponde ad ARP nella rete locale, oppure un router o un firewall segnala che è irraggiungibile.
C'è già un'operazione in corso sul socket, come una connect non bloccante non ancora terminata.
L'operazione è in corso: una connect non bloccante è iniziata e terminerà più tardi. Non è un errore; bisogna attendere con poll o select.
L'handle del file è obsoleto: in NFS, il file o la directory è stato eliminato o sostituito sul server. Si risolve riaprendo il percorso o rimontando.
La struttura deve essere ripulita: il file system ha rilevato una corruzione (in ext4 e XFS, con l'alias EFSCORRUPTED). Smontalo ed esegui fsck o xfs_repair.
Stesso valore:EFSCORRUPTED
Non è un file con nome XENIX. È un codice storico non più usato.
Nessun semaforo XENIX disponibile. È un codice storico non più usato.
È un file con nome XENIX. È un codice storico non più usato.
Errore di I/O remoto, per esempio di un dispositivo I2C o di un disco remoto che non ha risposto.
È stata superata la quota disco dell'utente o del gruppo.
Nessun supporto nel dispositivo, come un lettore ottico senza disco o un lettore di schede vuoto.
Il tipo di supporto non è corretto.
L'operazione è stata annullata, per esempio un I/O asincrono o un'attesa di io_uring.
La chiave necessaria non è nel keyring del kernel. Compare con i file system cifrati, come fscrypt o eCryptfs, quando la chiave non è stata caricata.
La chiave è scaduta. Anche PAM e Kerberos lo usano quando sono scaduti la password o il ticket.
La chiave è stata revocata.
Il servizio ha rifiutato la chiave.
Il proprietario di un mutex robusto è terminato senza rilasciarlo. Il nuovo proprietario deve rendere coerente lo stato protetto e chiamare pthread_mutex_consistent.
Lo stato protetto da un mutex robusto non può essere recuperato, perché il proprietario precedente è terminato e nessuno lo ha marcato come coerente.
L'operazione non è possibile perché la radio Wi-Fi o Bluetooth è bloccata da RF-kill. Controlla rfkill list, l'interruttore fisico o il tasto della modalità aereo.
La pagina di memoria ha un errore hardware e il kernel l'ha marcata come avvelenata.
Il tipo di file non è adatto all'operazione. In macOS e BSD esiste da molto tempo; in Linux è stato aggiunto di recente.
Ci sono troppi processi. BSD lo definisce per il limite di processi, anche se in pratica fork restituisce EAGAIN.
La struttura RPC non è corretta (Sun RPC, usato da NFS).
La versione di RPC non corrisponde (Sun RPC, usato da NFS).
Il programma RPC non è disponibile sul server.
La versione del programma RPC non corrisponde.
La procedura non esiste nel programma RPC.
Errore di autenticazione, per esempio durante il mount di una risorsa NFS.
Per l'operazione serve un autenticatore.
Il dispositivo è spento.
Errore del dispositivo, per esempio una stampante senza carta.
L'eseguibile non è valido.
L'eseguibile è per un altro tipo di CPU, come un binario solo x86_64 su un Mac con Apple Silicon senza Rosetta 2, o uno ARM su un Mac con Intel.
La versione della libreria condivisa non corrisponde.
Il file Mach-O è malformato o danneggiato.
L'attributo esteso non esiste; equivale all'ENODATA di Linux. Compare con xattr, per esempio quando si rimuove com.apple.quarantine da un file che non lo ha.
Nessuna policy registrata con quel nome nel MAC Framework.
La coda di uscita dell'interfaccia di rete è piena.
Le capability non sono sufficienti: lo restituiscono le chiamate limitate da una sandbox.
Il terminale che controllava il processo è stato chiuso o la sessione SSH si è interrotta. Molti demoni, come nginx, sshd o rsyslog, lo usano come richiesta di rileggere la configurazione; nohup, tmux e screen evitano che chiuda i processi all'uscita.
Interruzione da tastiera con Ctrl+C. Il programma può catturarlo per terminare in modo ordinato. Codice di uscita 130.
Uscita da tastiera con Ctrl+\. Termina il processo con dump della memoria; la JVM, invece, lo usa per stampare lo stato dei thread.
Il processore ha incontrato un'istruzione illegale: un binario compilato per una CPU più recente (per esempio, con AVX2 o AVX-512 su un processore che non le supporta), codice danneggiato o un salto verso dati.
Trap di debug: lo usano i debugger per i punti di interruzione. Se arriva senza debugger, di solito è un errore rilevato dal programma stesso, come i controlli di Swift in macOS.
Il processo ha chiamato abort(): un'asserzione fallita, un'eccezione C++ non catturata o una corruzione dell'heap rilevata dalla libreria C («double free or corruption»). Codice di uscita 134.
Stesso valore:SIGIOT
Errore di bus: un accesso a memoria non allineata in alcune architetture, o a una parte di un file mappato con mmap che non esiste più perché il file è stato troncato. Succede anche quando /dev/shm si riempie.
Eccezione aritmetica. Nonostante il nome, la causa più comune è una divisione intera per zero.
Termina il processo immediatamente: non può essere catturato, bloccato né ignorato. Lo inviano kill -9, l'OOM killer del kernel quando la memoria si esaurisce, e Docker o Kubernetes quando un container supera il suo limite di memoria (OOMKilled) o non termina in tempo dopo SIGTERM. Codice di uscita 137.
Segnale libero a cui ogni applicazione dà un proprio uso; per esempio, dd mostra il suo avanzamento e nginx riapre i log.
Violazione di segmento («Segmentation fault»): un accesso a memoria non valida, come dereferenziare un puntatore nullo, uscire dai limiti di un array o esaurire lo stack con una ricorsione infinita. Codice di uscita 139.
Secondo segnale libero a cui ogni applicazione dà un proprio uso.
Scrittura su una pipe o un socket senza lettore. È normale in cmd | head, dove il lettore termina prima; i server di solito lo ignorano e gestiscono l'errore EPIPE. Codice di uscita 141.
È scaduto il timer programmato con alarm o setitimer.
Richiesta di terminazione ordinata. È il segnale predefinito di kill, systemctl stop, docker stop e di Kubernetes quando elimina un pod; il processo dovrebbe chiudere le sue connessioni e uscire. Codice di uscita 143.
Errore di stack del coprocessore. Non è usato nel Linux attuale.
Un processo figlio è terminato, si è fermato o ha ripreso. Il padre deve raccoglierlo con wait; altrimenti il figlio resta come zombie.
Stesso valore:SIGCLD
Riprende un processo fermato, come fanno fg e bg nella shell.
Ferma il processo; non può essere catturato né ignorato. Si riprende con SIGCONT.
Sospensione dal terminale con Ctrl+Z. A differenza di SIGSTOP, il programma può catturarlo.
Un processo in background ha tentato di leggere dal terminale.
Un processo in background ha tentato di scrivere sul terminale con stty tostop attivo, o di modificarne la configurazione.
Sono arrivati dati urgenti (fuori banda) su un socket. Go lo usa internamente per interrompere le goroutine.
È stato superato il limite di tempo CPU del processo (ulimit -t).
È stata superata la dimensione massima di file consentita al processo (ulimit -f).
È scaduto il timer virtuale, che conta solo il tempo CPU del processo.
È scaduto il timer di profilazione, usato dai profiler.
È cambiata la dimensione della finestra del terminale; i programmi a schermo intero lo usano per ridisegnarsi.
C'è I/O disponibile su un descrittore configurato con O_ASYNC. In Linux, SIGPOLL è lo stesso segnale.
Stesso valore:SIGPOLL
Interruzione dell'alimentazione, che un software UPS segnala al sistema init.
Chiamata di sistema non valida. Oggi la causa abituale è un filtro seccomp che la blocca, come nei container.
Trap di emulazione (EMT). Esiste in macOS e BSD, ma non in Linux su x86 né su ARM.
Richiesta di informazioni con Ctrl+T nel terminale di macOS e BSD; molti comandi rispondono mostrando il loro avanzamento.
Il comando è terminato correttamente. È l'unico codice che indica successo: qualsiasi altro valore indica un errore.
Errore generico; ogni programma decide che cosa significa. Il dettaglio di solito è in ciò che il comando ha scritto su stderr. grep e diff lo usano con un altro significato: «nessuna corrispondenza trovata» o «i file sono diversi».
Uso errato di un comando interno della shell o errore di sintassi nello script. Molti programmi lo usano anche per opzioni non valide, e grep per errori reali.
Il comando è stato usato in modo errato: mancano argomenti, ce ne sono troppi o un'opzione non è corretta.
I dati di input hanno un formato non corretto.
Un file di input non esiste o non può essere letto.
L'utente indicato non esiste; lo usano soprattutto i programmi di posta.
Il nome host non esiste.
Un servizio necessario non è disponibile, oppure è fallito qualcosa che non rientra in un'altra categoria.
Errore interno del programma.
Errore del sistema operativo, come non riuscire a eseguire fork o a creare una pipe.
Manca un file di sistema, come /etc/passwd, oppure contiene un errore.
Impossibile creare un file di output.
Errore di input/output durante la lettura o la scrittura di un file.
Errore temporaneo: conviene riprovare più tardi. I server di posta lo usano per lasciare il messaggio in coda.
Il sistema remoto ha risposto qualcosa che non rispetta il protocollo.
Permessi insufficienti per l'operazione.
C'è un errore nella configurazione.
Il comando timeout lo ha terminato perché ha superato il tempo indicato.
È fallito docker run stesso prima di eseguire il container, per esempio per un'opzione errata o un errore del daemon. Anche GNU timeout lo restituisce quando a fallire è lui stesso.
Il file esiste, ma non può essere eseguito: manca il permesso di esecuzione, è una directory o è un binario di un'altra architettura. In Docker, il comando del container non è eseguibile.
Comando non trovato: non è installato, non è nel PATH o il nome è scritto male. Negli script compare anche quando manca l'interprete della riga #!; in Docker, quando il comando del container non esiste nell'immagine.
I codici maggiori di 128 indicano che un segnale ha terminato il processo, ma 128 non corrisponde a nessuno. Git lo usa per tutti i suoi errori fatali («fatal: …»), come un repository che non esiste o un errore di autenticazione durante il clone.
Il codice di uscita era fuori intervallo: exit -1 arriva come 255, perché si conservano solo 8 bit. Anche ssh lo restituisce quando fallisce la connessione o l'autenticazione, per distinguerlo dal codice del comando remoto.
I valori di Linux sono quelli di x86, x86-64 e ARM; Alpha, MIPS, SPARC e PA-RISC numerano diversamente alcuni errno e segnali. I messaggi in inglese sono quelli mostrati da strerror e strsignal in glibc, e in macOS quando sono diversi. I codici di uscita maggiori di 128 si interpretano come 128 più il numero del segnale, secondo la convenzione di bash, Docker e Kubernetes.
Come funziona
Quando una chiamata di sistema fallisce in Linux, restituisce -1 e lascia nella variabile errno un numero che indica il motivo: 2 è ENOENT, il file non esiste; 13 è EACCES, permesso negato. strerror converte quel numero nel testo che si vede a schermo, come «No such file or directory». Python lo mostra come [Errno 13], Node.js come code: 'ECONNREFUSED' e Go, Rust o Java con lo stesso testo. I numeri da 1 a 34 vengono dallo Unix originale e sono uguali in tutti i sistemi; i successivi li ha numerati ciascun sistema a modo suo, quindi ECONNREFUSED è 111 in Linux e 61 in macOS. Il nome è portabile; il numero no.
I segnali sono notifiche che il kernel o un altro processo inviano a un processo: SIGINT quando si preme Ctrl+C, SIGTERM per chiedergli di terminare, SIGKILL per terminarlo senza chiedere, SIGSEGV quando accede a memoria non valida. Ognuno ha un'azione predefinita, e quasi tutti possono essere catturati per fare altro. Quando un segnale uccide un processo, la shell riporta come codice di uscita 128 più il numero del segnale: 137 è SIGKILL (9), 139 è SIGSEGV (11) e 143 è SIGTERM (15). Docker e Kubernetes usano la stessa convenzione.
Il codice di uscita è il numero che un programma lascia quando termina: 0 significa successo e qualsiasi altro valore errore. Si conservano solo 8 bit, quindi va da 0 a 255. Le convenzioni sono poche: 126 e 127 li usa la shell quando non può eseguire o non trova il comando, da 64 a 78 li definisce sysexits.h di BSD, e il resto lo decide ogni programma, come grep, che restituisce 1 quando non trova nulla.
Esempi
Last State: Terminated · Reason: OOMKilled · Exit Code: 137137 = 128 + 9 · SIGKILLIl container ha superato il suo limite di memoria e il kernel lo ha terminato con SIGKILL. Bisogna alzare il limite in resources.limits.memory o capire perché il processo consuma così tanto; riavviarlo non risolve.Error: connect ECONNREFUSED 127.0.0.1:5432ECONNREFUSED · Linux 111 · macOS 61 · Connection refusedNode.js non è riuscito a connettersi a PostgreSQL perché nessuno è in ascolto sulla porta 5432. Se l'applicazione gira in un container, 127.0.0.1 è il container stesso e non la macchina: bisogna usare il nome del servizio del database.OSError: [Errno 48] Address already in useEADDRINUSE · Linux 98 · macOS 48Il 48 rivela che il programma gira su macOS: in Linux lo stesso errore è il 98. In entrambi i casi un altro processo usa già la porta; lsof -i :PORTA mostra quale.Casi d'uso
- Capire un errore di un'applicazione in Python, Node.js, Go o C che mostra solo il numero o il nome dell'errno.
- Scoprire, a partire dal codice di uscita, perché un container Docker si è chiuso o un pod Kubernetes si riavvia.
- Convertire un numero errno di macOS nel nome corretto, dato che dal 35 in poi non coincide con quello di Linux.
- Interpretare il codice di uscita di uno script, di un cron o di un job di CI fallito.
- Scegliere quale segnale inviare con kill e sapere che cosa fa il processo se non lo cattura.
- Scrivere una gestione degli errori portabile che confronti per nome anziché per numero.
Domande frequenti
Che cosa significa l'exit code 137?
Che il processo è stato terminato dal segnale 9, SIGKILL (128 + 9). La causa più comune è la memoria: il container ha superato il suo limite, e Kubernetes lo riporta come OOMKilled, oppure l'OOM killer del kernel ha scelto quel processo, cosa che resta in dmesg come «Out of memory: Killed process». Succede anche con docker kill, o quando il processo non termina entro il tempo previsto dopo SIGTERM: 10 secondi in docker stop e 30 in Kubernetes.
Che differenza c'è tra SIGTERM e SIGKILL?
SIGTERM chiede al processo di terminare, e il processo può catturarlo per chiudere le connessioni, salvare i dati e uscire. Con SIGKILL è il kernel a terminarlo all'istante, senza che il processo possa fare nulla. La cosa corretta è inviare SIGTERM, attendere qualche secondo e ricorrere a SIGKILL solo se è ancora vivo, che è ciò che fanno systemd, docker stop e Kubernetes.
Perché lo stesso errno ha un altro numero in macOS?
Perché POSIX definisce i nomi ma non i numeri. Da 1 a 34 tutti i sistemi hanno ereditato quelli dello Unix originale; dopo, BSD, da cui deriva macOS, e System V, seguito da Linux, li hanno numerati separatamente. Per questo conviene confrontare sempre per nome, con errno.ECONNREFUSED in Python, err.code in Node.js o la costante in C, e non con il numero.
Che differenza c'è tra EACCES ed EPERM?
EACCES («Permission denied») significa che i permessi del file o di una directory del percorso non lo consentono, oppure lo impedisce un'ACL o SELinux: si risolve con chmod, chown o la policy corrispondente. EPERM («Operation not permitted») significa che l'operazione in sé richiede privilegi, indipendentemente dai permessi, come cambiare il proprietario di un file o terminare un processo di un altro utente: servono root, una capability o la rimozione di un attributo come quello di immutabilità.
Come vedo il codice di uscita di un comando o di un container?
In bash e zsh, echo $? mostra quello dell'ultimo comando; in PowerShell, $LASTEXITCODE. In Docker, docker ps -a lo mostra nella colonna STATUS, come «Exited (137)». In Kubernetes, kubectl describe pod lo mostra in «Last State: Terminated», insieme al motivo, come OOMKilled o Error.