Certaines opérations n'acceptent pas n'importe quel nombre. Demander cent cinquante chiffres après la virgule ou un tableau de taille négative n'a pas de sens, et le langage le dit plutôt que de deviner.
C'est une erreur rare comparée aux autres, mais son message le plus connu n'a presque rien à voir avec les bornes d'un nombre.
Définition
Un RangeError est levé quand une valeur se situe en dehors de l'intervalle admis par l'opération demandée. Le type est correct, la valeur ne l'est pas.
const cas = [
() => new Array(-1),
() => (1.5).toFixed(101),
() => (255).toString(40),
() => "ab".repeat(-1),
];
for (const f of cas) {
try { f(); } catch (err) { console.log(err.name, "|", err.message); }
}
// RangeError | Invalid array length
// RangeError | toFixed() digits argument must be between 0 and 100Le message nomme systématiquement la borne attendue, ce qui rend la correction immédiate une fois l'appel identifié.
Les cas natifs à connaître
| Appel | Intervalle accepté |
|---|---|
new Array(n) | Un entier de 0 à environ quatre milliards |
toFixed(n) | De 0 à 100 chiffres |
toString(base) | Une base de 2 à 36 |
repeat(n) | Un nombre positif ou nul, et fini |
La Date produit aussi un RangeError avec le message Invalid time value, quand on demande le format normalisé d'une date impossible à interpréter. C'est le cas le plus courant en pratique, souvent déclenché par une chaîne mal formée reçue d'une interface.
Maximum call stack size exceeded
Voilà le message que tout le monde a déjà vu, et il est bien de type RangeError. La borne dépassée n'est pas celle d'un nombre, c'est la profondeur maximale de la pile d'appels.
function compter(n) {
return n === 0 ? 0 : 1 + compter(n - 1); // pas de garde en dessous de zéro
}
try {
compter(-1); // la condition d'arrêt n'est jamais atteinte
} catch (err) {
console.log(err.name, "|", err.message);
// RangeError | Maximum call stack size exceeded
}La cause est presque toujours une récursion sans condition d'arrêt correcte, ou une structure qui se contient elle-même. Vérifiez la condition avant de soupçonner la profondeur.
Une récursion légitime mais très profonde bute sur la même limite. La réécrire sous forme de boucle supprime le problème définitivement, alors qu'augmenter la taille de la pile ne fait que repousser l'échéance et dépend de l'environnement.
Questions fréquentes
Quelle est la profondeur maximale de la pile ?
Elle n'est fixée par aucune spécification et varie selon le moteur, la version et la taille des variables de chaque appel. Ne construisez jamais un algorithme sur une profondeur supposée : si le nombre d'appels dépend d'une donnée d'entrée, la boucle est le choix sûr.
Faut-il attraper un RangeError ?
Comme pour un TypeError, c'est généralement le signe d'un défaut à corriger. Une exception : la validation d'une date reçue de l'extérieur, où l'échec fait partie du parcours normal et mérite un try avec un message clair pour l'utilisateur.
Comment valider une date avant de la formater ?
En testant le résultat de getTime() : une date impossible à interpréter rend une valeur qui n'est pas un nombre. Un test avec Number.isNaN avant tout formatage évite l'erreur et permet d'afficher un message compréhensible plutôt qu'une panne.