Soluzione errore 1256 mysql "data truncated for column"
In un progetto di migrazione infrastrutturale per una PMI mi è capitato di seguire l'import di un dump MySQL da un server di produzione verso uno di backup, e di vederlo interrompersi a metà. Il conteggio delle righe importate non corrispondeva a quello della sorgente, e nei log comparivano decine di messaggi "Data truncated for column" durante l'esecuzione dell'import. È uno degli errori più comuni e, allo stesso tempo, più fraintesi quando si spostano dati fra ambienti MySQL configurati in modo diverso, e la sua diagnosi corretta non è quella che la maggior parte dei tutorial suggerisce.
TL;DR
- Errore reale: MySQL 1265
WARN_DATA_TRUNCATED(SQLSTATE01000), spesso cercato e citato come "1256" (che è invece un errore diverso, legato alla decompressione).- Causa: lo strict
sql_mode(STRICT_TRANS_TABLESoSTRICT_ALL_TABLES) promuove a errore bloccante la troncatura di un valore che eccede la colonna. Tipico quando importi un dump da un ambiente permissivo verso uno strict.- Fix corretto: pulisci i dati alla sorgente (o allarga la colonna), rigenera il dump e reimporta con strict mode attivo.
- Fix rapido per sbloccare l'import subito: esegui
SET sql_mode='';prima dell'import (o usaINSERT IGNORE), ma è un cerotto: i dati restano troncati.- Prevenzione: stesso
sql_modee charsetutf8mb4in tutti gli ambienti (sviluppo, staging, backup, produzione).
Cos'è davvero l'errore "Data truncated for column" e quando compare?
Partiamo da una precisazione utile, perché qui nasce la prima confusione. Questo errore viene spesso cercato e indicato come "errore 1256", ma il codice MySQL effettivo per "Data truncated for column" è il 1265 (WARN_DATA_TRUNCATED, SQLSTATE 01000). Il codice 1256 è invece ER_TOO_BIG_FOR_UNCOMPRESS, legato a problemi di decompressione ZLIB e completamente estraneo alla troncatura dei dati di colonna. Conoscere il codice giusto è il primo passo per cercare la diagnosi corretta invece di inseguire piste sbagliate. Il messaggio canonico ha questa forma:
ERROR 1265 (01000) at line 683: Data truncated for column 'column_name' at row 10Lo SQLSTATE 01000 è la classe "Warning" dello standard SQL. In condizioni di default permissive, MySQL tratterebbe questa situazione come un avviso non bloccante: troncherebbe il valore al limite della colonna e proseguirebbe. Quando però il sql_mode include STRICT_TRANS_TABLES o STRICT_ALL_TABLES, l'avviso viene promosso a errore vero e proprio e lo statement viene abortito. Su tabelle InnoDB (transazionali) l'intero statement viene sottoposto a rollback; su tabelle MyISAM (non transazionali) la riga viene rifiutata e lo statement si interrompe. È esattamente questo meccanismo a far fallire un import che, su un altro server, era passato senza un singolo errore.
Le cinque cause concrete della troncatura
Le situazioni che fanno scattare il troncamento sono cinque, e vale la pena distinguerle perché la soluzione cambia a seconda della causa.
Prima causa: lunghezza dei dati eccessiva rispetto alla colonna. È il caso più frequente. Una colonna VARCHAR(50) riceve un valore di 60 caratteri. Senza strict mode MySQL tronca a 50 e continua; con strict mode genera l'errore 1265 e aborta.
Seconda causa: incompatibilità di character set. Una colonna definita con charset latin1 riceve dati UTF-8 contenenti caratteri non rappresentabili. La sequenza di byte non si adatta al charset di destinazione e viene troncata al primo carattere problematico. Il caso più sottile è utf8 contro utf8mb4: gli emoji e i caratteri CJK supplementari richiedono 4 byte, e una colonna utf8mb3 (massimo 3 byte per carattere) li tronca.
Terza causa: valori ENUM non validi. Una colonna ENUM('Attivo', 'Inattivo', 'Sospeso') riceve il valore 'Archiviato'. Con strict mode è un errore 1265 immediato; senza strict mode MySQL inserisce una stringa vuota e genera un avviso silenzioso.
Quarta causa: perdita di precisione sui tipi numerici. Un valore 2.987654321 su una colonna DECIMAL(10,2) viene troncato a 2.99 con arrotondamento. Lo standard SQL considera questa una "data adjustment" e non un "range error", quindi anche con strict mode non sempre genera 1265: dipende dalla versione e dall'entità del troncamento. È una sottigliezza che inganna, perché in molti danno per scontato che lo strict mode catturi qualsiasi troncatura, mentre l'adattamento numerico al tipo di destinazione è un'operazione esplicitamente permessa dallo standard.
Quinta causa: caratteri nascosti negli import CSV. Un caso particolarmente subdolo è l'import di CSV generati su Windows che usano \r\n come terminatore di riga dove MySQL si aspetta un \n puro. Il \r resta attaccato al valore importato e, su colonne con vincoli esatti come gli ENUM, provoca una troncatura perché non corrisponde a nessun valore atteso.
La diagnosi corretta su un import tra ambienti
Il contesto tipico di questo errore è proprio quello dell'import di un dump da un server di produzione, con sql_mode permissivo, verso un server di backup con sql_mode strict. Le righe della tabella sorgente contengono valori che erano stati inseriti in produzione senza i vincoli che il server di destinazione applica. L'errore 1265 si manifesta perché il server strict rifiuta gli stessi dati che la sorgente aveva accettato silenziosamente, troncandoli. Il pattern di disallineamento di configurazione fra origine e destinazione è il classico generatore di questi sintomi, e capirlo indirizza subito verso la soluzione giusta.
Se gestisci import e migrazioni MySQL fra ambienti e ti trovi con conteggi di righe che non tornano, è esattamente il tipo di problema su cui intervengo: nel mio profilo professionale trovi l'esperienza concreta su audit della configurazione MySQL, allineamento di sql_mode e charset fra ambienti, e migrazione di dati legacy con normalizzazione automatica.
La soluzione operativa è una di queste tre, in ordine di preferibilità ingegneristica.
Soluzione 1, raccomandata: correggere i dati alla sorgente. Si identificano le righe che eccedono i vincoli, si normalizzano (riducendo i valori al limite della colonna o, se i dati sono legittimi, allargando la colonna stessa), si rigenera il dump dalla sorgente pulita e si importa nel server di destinazione con lo strict mode invariato. È la soluzione che risolve il problema invece di nasconderlo.
Soluzione 2: rilassare temporaneamente il sql_mode per il solo import. Si esegue SET sql_mode=''; (o si rimuovono i token strict) all'inizio della sessione di import, lasciando invariata la configurazione globale del server. È un approccio chirurgico, valido per sbloccare rapidamente, ma va usato sapendo che i dati che superano i vincoli verranno comunque troncati: è un modo per completare l'import, non per garantire l'integrità dei dati.
Soluzione 3: usare INSERT IGNORE. Modificando il dump per usare INSERT IGNORE al posto di INSERT, le troncature tornano a essere avvisi anche in strict mode e l'import procede. È la meno consigliabile, perché maschera il problema lasciando in tabella dati silenziosamente troncati che possono diventare bug funzionali più avanti.
Quella che applico quasi sempre nei progetti di consulenza è la prima. Il principio operativo è semplice: se il sql_mode del server di destinazione è strict per scelta, e da MySQL 8 lo è di default, e l'import fallisce, il messaggio è che la sorgente contiene dati che non avrebbero dovuto essere accettati. Aggirare il problema rendendo permissiva la destinazione significa replicarvi gli stessi difetti di qualità dei dati della sorgente. La via corretta è risalire all'origine, capire quale vincolo era stato indebolito in passato, pulire i dati e ripristinarlo.
Come trovare le righe che causano la troncatura
Prima di scegliere la soluzione conviene sapere esattamente quali dati stanno troncando, perché intervenire alla cieca porta a tagliare valori legittimi. Lo strumento più immediato è SHOW WARNINGS subito dopo lo statement che ha generato l'avviso: in modalità non-strict MySQL non aborta ma accumula gli avvisi, e questo comando li elenca riga per riga, indicando colonna e posizione. È il modo più rapido per ottenere l'inventario completo dei problemi in un colpo solo, eseguendo l'import una volta con strict mode disattivato proprio a scopo diagnostico, leggendo gli avvisi, e solo dopo decidendo come correggere.
Quando il sospetto è la lunghezza, si interroga direttamente la sorgente per stanare i valori che eccedono la definizione della colonna, così da quantificare il problema prima di toccarlo:
-- Trova i valori più lunghi del limite della colonna (es. VARCHAR(50))
SELECT id, CHAR_LENGTH(nome) AS lunghezza, nome
FROM clienti
WHERE CHAR_LENGTH(nome) > 50
ORDER BY lunghezza DESC;Per i caratteri nascosti, come il \r degli import CSV provenienti da Windows, una verifica mirata con HEX() su un campione rivela i byte di controllo che a occhio non si vedono. Questa fase diagnostica è quella che distingue una correzione consapevole da una rimozione cieca dei vincoli: una volta che sai quante righe e quali colonne sono coinvolte, capisci se hai davanti pochi record sporchi da ripulire a mano o un problema strutturale di definizione delle colonne che richiede una modifica dello schema.
Un equivoco frequente da chiarire: NO_AUTO_VALUE_ON_ZERO
Vale la pena chiarire un punto, perché è una fonte di confusione ricorrente in rete. Molte guide indicano il token NO_AUTO_VALUE_ON_ZERO di sql_mode come responsabile di questo errore. Non lo è. NO_AUTO_VALUE_ON_ZERO controlla esclusivamente il comportamento delle colonne AUTO_INCREMENT quando ricevono il valore esplicito zero: con il default di MySQL inserire zero genera il prossimo numero di sequenza esattamente come inserire NULL; con questo token attivo, zero resta zero e solo NULL genera il prossimo valore. È una modalità pensata per i dump: se una tabella ha valori zero in colonne AUTO_INCREMENT, mysqldump inserisce automaticamente SET sql_mode='NO_AUTO_VALUE_ON_ZERO'; proprio per preservarli al reimport. Con la troncatura dei dati non ha nulla a che fare: è una protezione ortogonale, dedicata a un problema diverso. La confusione nasce solo dal fatto che entrambi i token vivono nel parametro sql_mode e compaiono nei contesti di dump e import.
Best practice 2026 per evitare i disallineamenti tra ambienti
Quattro regole operative che applico nelle infrastrutture MySQL dei clienti per non ritrovarsi in queste situazioni.
Standardizza il sql_mode tra tutti gli ambienti. Sviluppo, staging, backup e produzione devono condividere lo stesso sql_mode. La policy che applico di default è STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO: è la configurazione più vicina allo standard SQL e cattura in fase di sviluppo i problemi di qualità dei dati che altrimenti si accumulano fino a manifestarsi durante un upgrade o una migrazione. La documentazione ufficiale MySQL sul sql_mode è il riferimento autoritativo per ogni token.
Unifica il charset a utf8mb4 ovunque. Il vecchio utf8 di MySQL, alias di utf8mb3, supporta solo i caratteri Unicode fino al Basic Multilingual Plane e tronca emoji, simboli matematici avanzati e ideogrammi CJK supplementari. Il moderno utf8mb4 copre l'intero Unicode, e per i progetti nuovi nel 2026 non c'è alcuna ragione tecnica per usare altro, sia a livello server sia a livello di tabella e colonna. La migrazione da utf8 a utf8mb4 è uno degli interventi più frequenti che faccio negli audit, e si collega alla diagnosi delle connessioni lente MySQL su VPS.
Per i database grandi, backup binario invece del dump testuale. Sopra dimensioni rilevanti o per applicazioni mission-critical, il dump testuale con mysqldump diventa lento e suscettibile esattamente a questa classe di problemi in fase di reimport. La strategia che documento nella guida ai backup incrementali di MySQL con XtraBackup senza blocchi sposta il problema su un livello diverso: backup fisici coerenti e recovery point granulari, senza ri-esecuzione di INSERT che possano fallire per troncatura.
Valida i dati a livello applicativo, non solo nel database. Nei progetti PHP e Laravel moderni non delego al database la validazione di lunghezza, formato e charset: la validazione avviene al confine dell'applicazione (FormRequest in Laravel, Constraint in Symfony), prima dell'INSERT. Il database resta l'ultima linea di difesa per l'integrità referenziale, ma i vincoli di lunghezza e tipo vengono catturati dall'applicazione con messaggi espliciti per l'utente. Questo riduce drasticamente la superficie di problemi che si manifestano come errore 1265 in produzione, perché i dati che arrivano al database sono già normalizzati.
Una nota importante su MySQL 8: dalla versione 8.0 lo strict mode è il default operativo, con STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION di serie. Significa che ogni installazione fresca ha già strict mode attivo, e nelle migrazioni da MySQL 5.7 a 8.0 il codice che funzionava silenziosamente con troncatura sotto la 5.7 inizia a fallire con l'errore 1265. È una delle fonti più frequenti di intoppi in quelle migrazioni, ed è esattamente la classe di problemi che lo strict mode è progettato per esporre: la soluzione corretta non è disattivarlo dopo l'upgrade, ma cogliere l'occasione per pulire i dati e i vincoli che sta giustamente segnalando. I riferimenti che consulto per la diagnostica sono il manuale ufficiale degli error code MySQL e la pagina sul sql_mode già citata.
Per chi gestisce database MySQL in produzione e si trova periodicamente con import che falliscono, valori troncati o disallineamenti silenziosi fra produzione e backup, contattami per un confronto diretto: di solito basta un audit della configurazione di tutti gli ambienti e di un campione rappresentativo dei dati per costruire un piano di pulizia e standardizzazione che elimina questa intera classe di problemi una volta per tutte.