L'essentiel
  • Un overflow float64 vers int16 (valeur 40 000 dans un registre 16 bits = -32 768 en Ada) a détruit la fusée Ariane 5 en 37 secondes le 4 juin 1996.
  • Le code Ada incriminé avait été copié d'Ariane 4 sans retester dans le contexte plus rapide d'Ariane 5, où la vitesse horizontale dépassait les limites du type de destination.
  • mypy avec --strict détecte les incompatibilités de types numériques avant l'exécution et aurait signalé ce bug à la compilation.
  • NumPy et Cython exposent Python aux mêmes overflows que C ; les types natifs Python (int, float) sont eux illimités.
  • 370 millions de dollars et 10 ans de développement détruits en 37 secondes parce que personne n'avait revérifié les hypothèses du code hérité.

Lecture complète : 14 min

4 juin 1996. 37 secondes après le décollage, Ariane 5 explose en vol.

10 ans de développement. 370 millions de dollars. Partis en fumée littéralement, au-dessus de la forêt guyanaise. L’enquête conclut en quelques semaines : la cause, c’est une conversion de nombre décimal en entier sur une valeur trop grande pour le type de destination. Une ligne de code Ada héritée d’Ariane 4, copiée sans vérification, qui a planté le système de navigation.

Ce bug a 30 ans. Il est encore pertinent aujourd’hui parce que la même erreur se produit en Python, en JavaScript, en Go, et dans tout langage où les types numériques ont des limites, du logiciel embarqué à la moindre API SaaS. Et parce que des outils comme mypy permettent de la détecter avant l’exécution. Avant l’explosion.

Voici l’histoire, le code, et ce que tu peux mettre en place dès aujourd’hui.


Ce qui s’est passé le 4 juin 1996

Ariane 5 est le successeur d’Ariane 4. Pour gagner du temps, les équipes ont réutilisé une partie du logiciel de navigation d’Ariane 4. Logique sur le papier : pourquoi réécrire ce qui marche ?

Le problème : Ariane 5 était beaucoup plus puissante qu’Ariane 4. Sa trajectoire initiale produisait une vitesse horizontale bien plus élevée. Cette valeur de vitesse horizontale, calculée en nombre décimal 64 bits, était convertie en entier 16 bits pour être transmise au système de référence inertielle.

Sur Ariane 4, cette valeur ne dépassait jamais la capacité d’un entier 16 bits. Un entier 16 bits signé peut stocker des valeurs entre -32 768 et 32 767. Sur Ariane 5, la valeur dépassait 32 767. La conversion a levé une Operand Error non rattrapée, et les deux systèmes de référence inertielle, le principal comme le secours, se sont arrêtés à 36,7 secondes. Privé de données d’attitude, le calculateur de bord a braqué les tuyères en butée. La fusée a désintégré sous les charges aérodynamiques vers 39 secondes, et le système de destruction automatique s’est déclenché.

Jusque là, c’est l’histoire qu’on raconte partout. Le rapport de la commission d’enquête en dit deux choses de plus, et ce sont les deux qui devraient t’intéresser.

La variable qui a débordé ne servait à rien. Elle s’appelle BH, pour Horizontal Bias, et c’est un indicateur de précision de l’alignement de la centrale inertielle. L’alignement, c’est la procédure qui trouve la verticale et le nord avant le décollage. Une fois la fusée en vol, cette fonction n’a plus aucun objet. Elle tournait quand même, pendant 50 secondes après le passage en mode vol, à cause d’une exigence rédigée plus de dix ans plus tôt pour Ariane 4 : elle permettait de reprendre un compte à rebours interrompu sans refaire un alignement complet de 45 minutes. Sur Ariane 5, cette possibilité n’existait plus. Le code est resté.

L’absence de protection était un choix documenté. Sept conversions de flottant vers entier pouvaient produire une Operand Error. Quatre ont été protégées, trois ne l’ont pas été, dont celle de BH. La raison invoquée était une cible de charge maximale de 80% pour le calculateur de la centrale inertielle. Pour justifier de laisser les trois autres sans filet, l’analyse a conclu qu’elles étaient soit physiquement bornées, soit dotées d’une large marge de sécurité. Le raisonnement était faux pour BH.

Et le rapport pointe pourquoi il était faux : aucune donnée de trajectoire d’Ariane 5 n’a été utilisée pour cette analyse. Il avait même été convenu entre les parties de ne pas inclure la trajectoire d’Ariane 5 dans les spécifications de la centrale inertielle.

Sur le coût, en revanche, ni le rapport d’enquête ni l’ESA ne publient de montant. Le chiffre de 370 millions de dollars qu’on lit partout, y compris dans le titre de cet article, est une estimation de presse qui additionne le lanceur et les quatre satellites Cluster. Ces satellites ont bien été perdus, aucun n’était réparable après récupération des débris.

Schéma de la conversion float64 vers int16 ayant causé la perte d'Ariane 5


Qu’est-ce qu’un overflow entier ?

Un overflow entier se produit quand une valeur numérique dépasse la capacité maximale du type qui est censé la stocker. En Ada, en C, en C++, les entiers ont des tailles fixes. Tenter de stocker 40 000 dans un entier 16 bits signé ne produit pas d’erreur visible : le nombre est simplement tronqué, et le résultat est un nombre incohérent qui va corrompre silencieusement tes calculs.

En C, un int16_t qui dépasse 32 767 revient à -32 768. C’est le comportement défini par la norme pour les types entiers signés.

#include <stdint.h>
#include <stdio.h>

int main() {
    int16_t vitesse = 32767;
    vitesse += 1;
    printf("%d\n", vitesse);  // Affiche -32768
    return 0;
}

Les bornes qui comptent tiennent en un tableau. Elles se calculent toutes de la même façon, deux puissance le nombre de bits, moins un pour le signe.

TypeBitsMinimumMaximum
int88-128127
int1616-32 76832 767
int3232-2 147 483 6482 147 483 647
int6464environ -9,2 milliards de milliardsenviron 9,2 milliards de milliards
int Pythonillimitéaucuneaucune

La dernière ligne est celle qui endort. En Python pur, un entier grandit tant qu’il reste de la mémoire, donc l’overflow entier n’existe pas. Il réapparaît dès que tu sors du Python pur : NumPy, Cython, struct, une colonne de base de données, un appel à une bibliothèque C.

Ariane 5 n’a pas planté sur un message d’erreur explicite. Elle a planté parce qu’une valeur dépassait la borne de la ligne int16, dans un langage qui, lui, refusait la conversion.


Reproduire le bug Ariane 5 en Python

Python standard n’a pas ce problème : ses entiers sont de précision arbitraire. Ils ne débordent jamais.

x = 32767
x += 1
print(x)  # Affiche 32768, pas -32768

Mais dès que tu utilises NumPy, qui est partout dans le code scientifique et de data science, le comportement change radicalement.

import numpy as np

vitesse_horizontale = np.int16(32767)
print(vitesse_horizontale + np.int16(1))
# Affiche -32768

# Simulation simplifiée du bug Ariane 5
def convertir_vitesse_navigation(vitesse_float64: np.float64) -> np.int16:
    # Aucune vérification des limites, exactement comme dans le code original
    return np.int16(vitesse_float64)

vitesse_ariane5 = np.float64(40000.0)
resultat = convertir_vitesse_navigation(vitesse_ariane5)
print(f"Vitesse convertie : {resultat}")
# Affiche : Vitesse convertie : -25536
# Un nombre absurde, interprété comme erreur système

Ce nombre, -25536, c’est ce que le système de navigation d’Ariane 5 a reçu à la place d’une vitesse mesurée. Il ne pouvait pas faire autrement que de paniquer.

La correction est triviale. Deux lignes :

import numpy as np

def convertir_vitesse_navigation_safe(vitesse_float64: np.float64) -> np.int16:
    INT16_MAX = np.iinfo(np.int16).max  # 32767
    INT16_MIN = np.iinfo(np.int16).min  # -32768
    
    if vitesse_float64 > INT16_MAX or vitesse_float64 < INT16_MIN:
        raise OverflowError(
            f"Vitesse {vitesse_float64} hors limites int16 [{INT16_MIN}, {INT16_MAX}]"
        )
    
    return np.int16(vitesse_float64)

# Test
try:
    resultat = convertir_vitesse_navigation_safe(np.float64(40000.0))
except OverflowError as e:
    print(f"Erreur détectée avant conversion : {e}")
    # Comportement de sécurité ici : log, alerte, valeur par défaut

Sur Ariane 5, lever une exception aurait stoppé proprement le calcul. Le système de navigation aurait reçu un signal d’erreur explicite plutôt qu’une valeur corrompue silencieuse. Peut-être qu’il aurait pu continuer en mode dégradé.


Comment détecter un overflow avec mypy

mypy est un vérificateur de types statique pour Python. Il analyse ton code sans l’exécuter et signale les incohérences de types avant que tu ne déploies quoi que ce soit. Il ne détecte pas directement les overflows numériques, mais il détecte les conversions de types dangereuses et les fonctions qui reçoivent des types inattendus.

Ce que mypy voit, et ce qu’il ne verra jamais

Autant le dire tout de suite pour éviter la fausse sécurité, qui est exactement le piège dans lequel les équipes d’Ariane 5 sont tombées. mypy travaille sur les types, pas sur les valeurs. Il te dira qu’une fonction annoncée comme rendant un np.int16 reçoit bien un np.float64 en entrée, donc qu’une conversion a lieu à cet endroit. Il ne te dira jamais que la valeur qui passera là en production vaudra 40 000.

C’est précisément la frontière du problème d’Ariane 5. La conversion était visible dans le code, elle était même connue et analysée. Ce qui manquait, c’était la donnée de trajectoire qui aurait montré que BH sortirait de la plage. Un vérificateur de types repère l’endroit où il faut réfléchir. Il ne réfléchit pas à ta place.

D’où la règle pratique : mypy pour trouver les points de conversion, une validation à l’exécution pour vérifier les bornes à ces points là.

Mettre mypy en place sur ce type de bug

pip install mypy

Exemple de code sans annotations de type :

# navigation.py
import numpy as np

def convertir_vitesse(v):
    return np.int16(v)

vitesse = 40000.0
nav_value = convertir_vitesse(vitesse)

mypy ne peut pas déduire grand chose ici. Maintenant avec des annotations :

# navigation_typed.py
import numpy as np
from numpy.typing import NDArray

def convertir_vitesse(v: np.float64) -> np.int16:
    return np.int16(v)

vitesse: np.float64 = np.float64(40000.0)
nav_value: np.int16 = convertir_vitesse(vitesse)
mypy navigation_typed.py --strict

mypy ne lèvera pas d’erreur ici parce que la conversion est techniquement valide en termes de types. Mais en combinant mypy avec une fonction de validation typée et un plugin comme beartype ou des assertions explicites, tu crées une défense en profondeur :

from typing import assert_never
import numpy as np

def convertir_vitesse_validee(v: np.float64) -> np.int16:
    limite = np.iinfo(np.int16)
    assert limite.min <= v <= limite.max, (
        f"Overflow détecté : {v} hors de [{limite.min}, {limite.max}]"
    )
    return np.int16(v)

mypy vérifiera que v est bien de type np.float64 à l’appel. Si tu passes un int Python classique par erreur, mypy te le signale avant l’exécution.

J’utilise mypy sur Copyboost depuis que j’ai eu un bug subtil de type sur les données Supabase. Ca m’a économisé plusieurs cycles de debug. J’en parle dans mon article sur les 5 erreurs Python sur VPS qui m’ont coûté des heures.

La config mypy minimale que j’utilise :

# mypy.ini
[mypy]
python_version = 3.11
strict = true
warn_return_any = true
warn_unused_ignores = true

Tests unitaires : la deuxième ligne de défense

mypy analyse les types. Les tests unitaires vérifient le comportement aux limites. Les deux sont complémentaires.

Pour le bug Ariane 5, le test unitaire qui aurait tout changé :

import pytest
import numpy as np
from navigation import convertir_vitesse_navigation_safe

def test_conversion_dans_les_limites():
    assert convertir_vitesse_navigation_safe(np.float64(1000.0)) == np.int16(1000)

def test_conversion_limite_haute():
    assert convertir_vitesse_navigation_safe(np.float64(32767.0)) == np.int16(32767)

def test_conversion_limite_basse():
    assert convertir_vitesse_navigation_safe(np.float64(-32768.0)) == np.int16(-32768)

def test_overflow_positif_leve_exception():
    with pytest.raises(OverflowError):
        convertir_vitesse_navigation_safe(np.float64(32768.0))

def test_overflow_negatif_leve_exception():
    with pytest.raises(OverflowError):
        convertir_vitesse_navigation_safe(np.float64(-32769.0))

def test_valeur_ariane5_leve_exception():
    # La valeur réelle qui a détruit Ariane 5
    with pytest.raises(OverflowError):
        convertir_vitesse_navigation_safe(np.float64(40000.0))
pytest test_navigation.py -v

Output d'un test pytest qui passe avec la fonction de conversion sécurisée

Six tests. Trois minutes à écrire. Des décennies de leçon condensées.

Le rapport d’enquête sur Ariane 5 note explicitement que le code Ada original d’Ariane 4 n’avait pas été retesté dans les conditions de vol d’Ariane 5. Les tests existants validaient le comportement normal, pas les cas limites. C’est exactement ce que test_valeur_ariane5_leve_exception aurait capturé.

Quand tu réutilises du code existant dans un nouveau contexte, les anciens tests ne suffisent plus. Le nouveau contexte crée de nouvelles hypothèses. Ces hypothèses doivent être testées.


Questions fréquentes

Qu’est-ce que le bug Ariane 5 exactement ?

Le 4 juin 1996, la fusée Ariane 5 a explosé 37 secondes après son décollage à cause d’une erreur de conversion numérique dans son logiciel de navigation. Une valeur de vitesse horizontale, représentée en nombre décimal 64 bits, a été convertie en entier 16 bits sans vérification des limites. La valeur dépassait la capacité du type entier, ce qui a produit un nombre corrompu interprété comme une erreur système fatale.

Un overflow entier peut-il se produire en Python ?

Python natif ne produit pas d’overflow sur ses entiers car ils sont de taille arbitraire. Mais dès que tu utilises NumPy, Pandas ou tout code qui manipule des tableaux typés, les entiers ont des limites fixes comme en C. Un np.int16 déborde exactement comme un int16_t en C. Le bug Ariane 5 est totalement reproductible avec NumPy.

Comment mypy aide à prévenir les bugs de type numérique ?

mypy vérifie statiquement que les types passés à tes fonctions correspondent aux types attendus. Il ne détecte pas les overflows numériques directement, mais il détecte les conversions de types implicites et les fonctions mal utilisées avant l’exécution. Combiné à des assertions de validation aux limites dans le code, il forme une défense solide contre ce type de bug.

Pourquoi le code d’Ariane 4 a-t-il été réutilisé sans tests supplémentaires ?

Selon le rapport de la commission d’enquête de 1996, la décision de réutiliser ce module venait d’une analyse de risque incorrecte. L’équipe a estimé que le module était « correct » parce qu’il fonctionnait sur Ariane 4. Elle n’a pas vérifié si les valeurs d’entrée possibles sur Ariane 5 restaient dans les mêmes plages. C’est un biais classique : confondre « le code fonctionne » avec « le code est correct dans ce nouveau contexte ».

Quel est le coût total du bug Ariane 5 ?

Aucune source officielle ne le chiffre. Ni le rapport de la commission d’enquête, ni les communiqués de l’ESA sur le vol 501 ne publient de montant. L’estimation de 370 millions de dollars qui circule additionne le lanceur et les quatre satellites Cluster, dont aucun n’était réparable après récupération des débris. Le coût indirect, en délais sur le programme et en reconfiguration, n’a pas non plus été publié.

La variable qui a débordé était-elle vraiment inutile ?

Après le décollage, oui. BH était un indicateur de précision de l’alignement de la centrale inertielle, une fonction qui n’a de sens qu’au sol. Elle continuait à tourner 50 secondes après le passage en mode vol à cause d’une exigence écrite plus de dix ans plus tôt pour les Ariane précédentes, qui permettait de reprendre un compte à rebours interrompu sans refaire un alignement complet. Sur Ariane 5, ce scénario n’existait plus. La commission d’enquête relève d’ailleurs qu’il est douteux de laisser une fonction d’alignement s’exécuter après le décollage.


Ce que tout dev devrait retenir de ce crash

Le code qui marchait hier ne marche pas forcément dans un nouveau contexte. C’est la leçon numéro un d’Ariane 5.

La leçon numéro deux : les limites de types sont des contrats implicites. Quand tu convertis un float en int, tu fais le pari que la valeur tiendra dans la destination. Ce pari doit être vérifié explicitement, pas assumé.

Trois choses à faire dès cette semaine :

  1. Installe mypy sur ton projet et active le mode strict
  2. Ajoute une validation aux limites sur toute conversion numérique qui traite des données externes ou calculées
  3. Ecris les tests de cas limites avant d’écrire le code principal, au moins sur les fonctions numériques critiques

Si tu réutilises du code existant dans un nouveau contexte, recommence les tests depuis zéro. « Ca marchait avant » n’est pas un argument de sécurité.

Et la leçon numéro trois, la plus facile à appliquer ce soir : supprime le code qui ne sert plus. Ariane 5 a été détruite par une fonction qui n’avait aucune raison de tourner.

Dernière mise à jour : juin 2026

Cet article fait partie de la série 10 bugs informatiques qui ont tué, crashé et coûté des milliards.