#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
{
"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.
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
error | Statut | Signification | Conduite à tenir |
|---|---|---|---|
unauthorized | 401 | Clé 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és | Vérifier la clé, en créer une neuve. Vérifier aussi qu’on appelle bien cms.webcosa.com |
portee_insuffisante | 403 | Clé de portée lecture sur une écriture | Utiliser une clé themes. La portée ne se modifie pas : il faut une nouvelle clé |
site_interdit | 403 | X-Webcosa-Site-Cible désigne un site qui n’est pas accessible au porteur | Vérifier le slug. Le champ site de GET /api/themes donne la bonne valeur |
no_site | 409 | Le compte n’a aucun site | Rien à faire côté API : créer un site depuis le CMS |
trop_de_tentatives | 429 | Plus de dix clés invalides présentées dans l’heure | Arrêter la boucle, corriger la clé, attendre |
indisponible | 503 | L’installation n’a pas de clé de service : l’authentification par clé est hors service | Panne de configuration côté serveur. Réessayer, puis signaler |
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
error | Statut | Signification | Conduite à tenir |
|---|---|---|---|
site_inactif | 402 | Le site est suspendu, ou son essai est terminé. Toutes les écritures sont refusées | Reprendre 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
error | Statut | Signification | Conduite à tenir |
|---|---|---|---|
invalid_input | 400 | Corps absent, illisible, ou hors des bornes du schéma. Aussi : paramètre id ou chemin manquant | Relire les bornes de la route. PATCH exige un id uuid, pas un identifiant court |
introuvable | 404 | Le thème n’existe pas, ou n’est pas de ce site — les deux se répondent pareil | Vérifier l’uuid, et le site visé |
fichier_introuvable | 404 | Le chemin n’existe pas dans ce thème | Le comparer à l’arborescence. La casse compte, il n’y a aucune normalisation |
theme_inconnu | 400 | origine ne désigne aucun thème du catalogue | Les valeurs sont origo, forge, vela, piazza |
theme_publie | 409 | On tente de supprimer le thème en ligne | En publier un autre d’abord |
fichier_requis | 409 | On tente de supprimer layout/theme.liquid, templates/index.json ou config/settings_schema.json | Ces trois-là se remplacent par un PUT, ils ne se retirent pas |
trop_de_cles | 409 | Vingt clés vivantes sur le compte | Ré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.
error | Statut | Signification |
|---|---|---|
traversee | 400 | Le chemin commence par /, contient .. ou une barre oblique inversée |
hors_dossier | 400 | Pas exactement deux segments, ou dossier inconnu |
nom | 400 | Le nom du fichier contient autre chose que lettres, chiffres, points, tirets et tirets bas — ou ne commence pas par une lettre ou un chiffre |
extension | 400 | Extension non admise dans ce dossier |
syntaxe | 400 | L’analyse Liquid ou JSON a échoué. message porte l’erreur de l’analyseur, avec ligne et colonne |
trop_de_fichiers | 400 | 120 fichiers atteints, à la création d’un fichier ou à l’import |
fichier_trop_gros | 400 | Une entrée d’archive dépasse 524 288 unités de code UTF-16 |
chemin_invalide | 400 | Une entrée d’archive est refusée par l’une des quatre règles ci-dessus |
fichier_requis_manquant | 400 | L’archive n’a pas les trois fichiers indispensables |
vide | 400 | L’archive ne contient aucun fichier |
archive_invalide | 400 | Le corps n’a pas la forme d’un export Webcosa, ou format_version n’est pas 1 |
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
error | Statut | Signification |
|---|---|---|
save_failed | 500 | Une écriture a échoué en base |
load_failed | 500 | Une lecture a échoué en base |
publication_impossible | 500 | La publication n’a pas abouti |
creation_impossible | 400 | La ligne du thème n’a pas pu être créée |
ecriture_impossible | 400 | Les 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.
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 invalidesChaque 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éeLes 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 : 10Dix tentatives. La onzième est refusée.
Sur quelle fenêtrefenêtre fixedéfaut : 1 heureFixe, 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{ "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.
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.
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
401, 403, 429 : arrêter la boucle
Ces trois-là ne se réparent pas en réessayant. Un script qui relance un
pousseraprès un401transforme une clé périmée en dix tentatives, puis en429. Le CLI s’arrête ; faites de même.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é.400 : lire `error`, pas `message`
Six causes derrière un même statut.
syntaxedemande de corriger un fichier,trop_de_fichiersd’en supprimer un,invalid_inputde relire le schéma de la route. Voir Fichiers et Thèmes.404 : distinguer le thème du fichier
introuvableveut dire que l’uuid ou le site est faux.fichier_introuvableveut dire que le thème est bon et que le chemin ne l’est pas.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.

