Aller au contenu

#Codes d’erreur

Un intégrateur passe l’essentiel de son temps sur les 4xx. Cette page liste tous les codes que l’API émet, ce qui les a déclenchés, et la conduite à tenir — puis explique la seule limite de débit du produit, ce qu’elle arrête et ce qu’elle n’arrête pas.

#La forme d’une réponse d’erreur

Toujours ces deux champs, au plusjson
{
  "error": "fichier_requis",
  "message": "Ce fichier est indispensable au thème : il ne peut pas être supprimé."
}

error est un code stable, en minuscules avec des tirets bas. C’est lui qu’on compare en code, et lui seul : il ne changera pas de nom sans que le journal le dise.

message est une phrase rédigée en français, destinée à être affichée telle quelle. Elle n’apparaît que là où le code seul ne suffirait pas à savoir quoi faire. Ne la comparez jamais — elle peut être reformulée sans préavis.

Un seul refus porte un troisième champ : site_inactif ajoute etat. Aucun autre code n’en emporte.

Attention

Ne te fie pas au statut HTTP seul. 400 couvre à lui seul un corps mal formé, un chemin hors dossier, une extension refusée, une erreur de syntaxe Liquid, une archive illisible et un plafond de fichiers atteint — six situations qui n’appellent pas la même réaction. 404, lui, désigne tantôt un thème, tantôt un fichier, et les deux ont des codes distincts.

#Authentification et accès

errorStatutSignificationConduite à tenir
unauthorized401Clé inconnue, révoquée ou périmée — les trois donnent la même réponse. Aussi : aucune clé et aucune session, ou une route qui n’est pas ouverte aux clésVérifier la clé, en créer une neuve. Vérifier aussi qu’on appelle bien cms.webcosa.com
portee_insuffisante403Clé de portée lecture sur une écritureUtiliser une clé themes. La portée ne se modifie pas : il faut une nouvelle clé
site_interdit403X-Webcosa-Site-Cible désigne un site qui n’est pas accessible au porteurVérifier le slug. Le champ site de GET /api/themes donne la bonne valeur
no_site409Le compte n’a aucun siteRien à faire côté API : créer un site depuis le CMS
trop_de_tentatives429Plus de dix clés invalides présentées dans l’heureArrêter la boucle, corriger la clé, attendre
indisponible503L’installation n’a pas de clé de service : l’authentification par clé est hors servicePanne de configuration côté serveur. Réessayer, puis signaler
Note

unauthorized ne dit jamais pourquoi. Inconnue, révoquée, périmée : la réponse au porteur serait de toute façon la même, et lui dire laquelle des trois renseignerait quelqu’un qui teste des clés volées.

Pour savoir laquelle, regardez la liste dans le CMS : revoquee_le et expire_le y répondent en une seconde.

#Facturation

errorStatutSignificationConduite à tenir
site_inactif402Le site est suspendu, ou son essai est terminé. Toutes les écritures sont refuséesReprendre un abonnement depuis le CMS. Aucun contournement par l’API

402 Payment Required et non 403, parce que « tu n’as pas le droit » et « ta formule ne le couvre pas » appellent deux interfaces très différentes — un message d’erreur d’un côté, une proposition de changer de formule de l’autre — et un client ne peut pas les distinguer si le serveur répond la même chose.

Le champ etat accompagne le refus et vaut essai, actif, retard, expire ou aucun. Il est informatif : c’est site_inactif qui décide, pas lui.

Les lectures restent ouvertes. DELETE /api/themes aussi — retirer un brouillon ne change rien à ce que voient les visiteurs, et un site en fin d’essai peut encore faire le ménage chez lui.

#Requête et ressource

errorStatutSignificationConduite à tenir
invalid_input400Corps absent, illisible, ou hors des bornes du schéma. Aussi : paramètre id ou chemin manquantRelire les bornes de la route. PATCH exige un id uuid, pas un identifiant court
introuvable404Le thème n’existe pas, ou n’est pas de ce site — les deux se répondent pareilVérifier l’uuid, et le site visé
fichier_introuvable404Le chemin n’existe pas dans ce thèmeLe comparer à l’arborescence. La casse compte, il n’y a aucune normalisation
theme_inconnu400origine ne désigne aucun thème du catalogueLes valeurs sont origo, forge, vela, piazza
theme_publie409On tente de supprimer le thème en ligneEn publier un autre d’abord
fichier_requis409On tente de supprimer layout/theme.liquid, templates/index.json ou config/settings_schema.jsonCes trois-là se remplacent par un PUT, ils ne se retirent pas
trop_de_cles409Vingt clés vivantes sur le compteRévoquer avant de créer

#Format d’un fichier ou d’une archive

Ces codes viennent de la validation du format des thèmes. Ils sont identiques que l’on écrive un fichier, qu’on duplique un thème ou qu’on importe une archive.

errorStatutSignification
traversee400Le chemin commence par /, contient .. ou une barre oblique inversée
hors_dossier400Pas exactement deux segments, ou dossier inconnu
nom400Le nom du fichier contient autre chose que lettres, chiffres, points, tirets et tirets bas — ou ne commence pas par une lettre ou un chiffre
extension400Extension non admise dans ce dossier
syntaxe400L’analyse Liquid ou JSON a échoué. message porte l’erreur de l’analyseur, avec ligne et colonne
trop_de_fichiers400120 fichiers atteints, à la création d’un fichier ou à l’import
fichier_trop_gros400Une entrée d’archive dépasse 524 288 unités de code UTF-16
chemin_invalide400Une entrée d’archive est refusée par l’une des quatre règles ci-dessus
fichier_requis_manquant400L’archive n’a pas les trois fichiers indispensables
vide400L’archive ne contient aucun fichier
archive_invalide400Le corps n’a pas la forme d’un export Webcosa, ou format_version n’est pas 1
Astuce

chemin_invalide est la version « archive » des quatre refus de chemin : à l’import, on sait qu'une entrée est refusée, pas laquelle ni pourquoi. Quand un import échoue là-dessus, écrivez les fichiers un par un avec PUT /api/themes/<id>/fichiers : le refus devient précis.

#Pannes serveur

errorStatutSignification
save_failed500Une écriture a échoué en base
load_failed500Une lecture a échoué en base
publication_impossible500La publication n’a pas abouti
creation_impossible400La ligne du thème n’a pas pu être créée
ecriture_impossible400Les fichiers n’ont pas pu être écrits. Le thème créé est alors effacé — pas de coquille laissée derrière

Les deux derniers sortent en 400 et non en 500 : ils remontent de la validation d’installation, qui rend un seul statut pour toutes ses raisons. C’est un écart assumé, à connaître si tu branches une alerte sur les 5xx — ces deux-là ne s’y verront pas.

Astuce

Rejouer une requête après un 5xx est sans danger sur cette API : PUT et DELETE sont idempotents, PATCH l’est aussi, et POST crée un thème de plus — visible et supprimable. Aucune opération n’est destructrice par accident.

#La limitation de débit

Un seul compteur dans toute l’API, et il ne porte pas sur les requêtes réussies.

Ce qui est comptéclés invalides

Chaque secret présenté qui ne correspond à aucune clé vivante. Une clé valable n’incrémente rien, quel que soit le nombre d’appels.

Par quoiempreinte tronquée

Les huit premiers caractères hexadécimaux du SHA-256 du secret présenté. Deux secrets différents ont donc deux compteurs différents.

Combienentierdéfaut : 10

Dix tentatives. La onzième est refusée.

Sur quelle fenêtrefenêtre fixedéfaut : 1 heure

Fixe, pas glissante : la fenêtre démarre à la première tentative et le compteur repart à zéro une heure plus tard. Le quota ne se libère donc pas progressivement.

Ce que ça rend429
json
{ "error": "trop_de_tentatives" }

Sans en-tête Retry-After : la fenêtre est d’une heure, et rien ne redonne le droit avant.

#Ce que ce compteur arrête, et ce qu’il n’arrête pas

Il n’arrête pas une recherche exhaustive de secret. 256 bits ne se devinent pas, et de toute façon chaque essai aurait une empreinte différente, donc son propre compteur. Prétendre le contraire serait se raconter une histoire.

Ce qu’il arrête, c’est le cas réel et fréquent : une clé révoquée ou périmée qu’un CI continue de présenter en boucle, plusieurs fois par minute, indéfiniment. Sans compteur, chaque tentative coûte un aller-retour de base — et un CI mal réglé fait plus de dégâts qu’un attaquant.

Note

Le compteur porte sur l'empreinte, pas sur l’adresse IP, et c’est un choix. L’IP d’une intégration continue change à chaque exécution ; celle d’un bureau est partagée par tout le monde. Compter par IP raterait le fautif et punirait ses collègues.

L’empreinte est tronquée à huit caractères parce que la clé de compteur finit dans une table lisible par le service, et qu’il n’y a aucune raison d’y déposer l’empreinte complète d’un secret — même invalide, celui qui le présente peut très bien être un utilisateur légitime qui s’est trompé de variable d’environnement.

Un refus déjà prononcé est mémorisé une minute dans le processus qui l’a rendu : la onzième tentative et les suivantes repartent sans le moindre accès à la base. C’est ce que le compteur promettait et ne tenait pas au départ — il était consulté après la vérification, donc il ne pouvait rien économiser.

Attention

Si le compteur est indisponible — migration non jouée, service mal configuré — il n’y a pas de refus supplémentaire : la décision normale s’applique, et c’est un 401. Une limitation de débit en panne ne doit pas se transformer en panne de plus.

#Que faire selon le code

  1. 401, 403, 429 : arrêter la boucle

    Ces trois-là ne se réparent pas en réessayant. Un script qui relance un pousser après un 401 transforme une clé périmée en dix tentatives, puis en 429. Le CLI s’arrête ; faites de même.

  2. 402 : c’est de la facturation, pas de la technique

    Aucun en-tête, aucune option, aucun autre mode d’authentification ne contourne site_inactif. Le contournement a existé — une clé écrivait là où le navigateur était refusé — et il a été fermé.

  3. 400 : lire `error`, pas `message`

    Six causes derrière un même statut. syntaxe demande de corriger un fichier, trop_de_fichiers d’en supprimer un, invalid_input de relire le schéma de la route. Voir Fichiers et Thèmes.

  4. 404 : distinguer le thème du fichier

    introuvable veut dire que l’uuid ou le site est faux. fichier_introuvable veut dire que le thème est bon et que le chemin ne l’est pas.

  5. 5xx : réessayer une fois, puis signaler

    Rien n’est perdu à rejouer. Si le refus persiste, ce n’est pas la requête qui est en cause.