# Dépannage

Trouvez ce qui ne va pas et remettez votre formulaire en marche. Chaque section part de ce que vous voyez,
montre comment le vérifier et donne la solution. Formerie renvoie des codes stables, et cette page utilise
leurs noms exacts.

Les sections :

- [Mon courriel n’est pas arrivé](#mon-courriel-nest-pas-arrivé)
- [Une soumission a été refusée](#une-soumission-a-été-refusée)
- [Le formulaire ne s’affiche pas](#le-formulaire-ne-saffiche-pas)
- [Une erreur CORS ou d’origine](#une-erreur-cors-ou-dorigine)
- [La vérification a échoué](#la-vérification-a-échoué)

## Mon courriel n’est pas arrivé

**Symptôme :** quelqu’un a rempli le formulaire, et le courriel n’est jamais arrivé.

**Comment vérifier :** ouvrez **Livraisons** dans l’application et trouvez la réponse par formulaire et par
date. Chaque ligne donne un état et un diagnostic, avec un code, un résumé et une prochaine étape. Les mêmes
détails se trouvent sur la réponse elle-même, sous **Soumissions**. Cherchez ensuite ce que vous voyez dans ce
tableau.

| Ce que vous voyez | Ce que ça veut dire | Que faire |
| --- | --- | --- |
| Aucune réponse sous **Soumissions** | Elle a été refusée avant d’être conservée | Consultez [Une soumission a été refusée](#une-soumission-a-été-refusée) |
| Une réponse sans livraison | Le formulaire n’avait aucun destinataire : elle a seulement été conservée | Ajoutez un destinataire sous **Livraison**. Les nouvelles réponses seront envoyées par courriel. Les précédentes n’ont jamais été envoyées, et un nouvel essai ne les enverra pas |
| **En attente** | Le courriel attend sa tentative | Patientez un moment |
| **Nouvel essai** | Un problème temporaire chez le fournisseur. Formerie essaie jusqu’à 5 fois, à 60 secondes d’intervalle | Patientez, sauf si le diagnostic est `DELIVERY_STALLED` |
| **Échoué** | Le courriel n’a pas pu partir | Trouvez le code dans le prochain tableau, corrigez la cause, puis choisissez **Réessayer l’envoi** |
| **Livrée** | Le fournisseur a accepté le courriel | Consultez [Livré, mais pas dans la boîte de réception](#livré-mais-pas-dans-la-boîte-de-réception) |

### Les codes de diagnostic de livraison

| Code | Ce que dit l’application | Solution |
| --- | --- | --- |
| `DELIVERY_RECIPIENTS_UNAVAILABLE` | Aucun destinataire actif et vérifié n’est configuré pour ce formulaire | Faites confirmer le destinataire par courriel, ou ajoutez-en un autre, sous **Livraison** |
| `DELIVERY_SENDER_UNAVAILABLE` | L’identité d’expéditeur choisie n’est pas active ou vérifiée | Confirmez l’expéditeur sous **Expéditeurs**, ou remettez **Envoyer depuis** sur l’expéditeur par défaut de Formerie |
| `DELIVERY_CREDENTIALS_MISSING` | Il manque des identifiants requis pour le fournisseur d’envoi | Reconnectez le fournisseur sous **Destinations** |
| `DELIVERY_PROVIDER_NOT_FOUND` | Le fournisseur de courriel configuré n’a pas pu être utilisé | Vérifiez le fournisseur sous **Destinations** et dans l’onglet **Livraison** |
| `DELIVERY_PROVIDER_UNREACHABLE` | Le fournisseur d’envoi n’a pas pu être joint | Vérifiez l’état du fournisseur, puis réessayez |
| `DELIVERY_PROVIDER_ERROR` | Le fournisseur n’a pas accepté l’envoi | Vérifiez l’état du fournisseur et vos réglages chez lui, puis réessayez |
| `DELIVERY_FAILED` | L’envoi a échoué avant que le fournisseur accepte le message | Vérifiez l’expéditeur, les destinataires et le fournisseur, puis réessayez |
| `DELIVERY_STALLED` | Les nouvelles tentatives d’envoi ont cessé après une erreur temporaire | Ouvrez la réponse et réessayez |
| `DELIVERY_PROVIDER_UNREACHABLE_RETRYING` | Le fournisseur d’envoi n’a pas pu être joint | Rien pour l’instant. Formerie va réessayer |
| `DELIVERY_PROVIDER_TEMPORARY_ERROR` | Le fournisseur a renvoyé une erreur d’envoi temporaire | Rien pour l’instant. Formerie va réessayer |
| `DELIVERY_QUEUED`, `DELIVERY_WAITING_FOR_ATTEMPT` | L’envoi attend une tentative | Rien pour l’instant |
| `DELIVERY_ACCEPTED`, `DELIVERY_COMPLETED` | Le fournisseur a accepté le courriel | Consultez la prochaine section s’il n’est toujours pas arrivé |

### Livré, mais pas dans la boîte de réception

**Livrée** veut dire que le fournisseur a pris le courriel. Cela ne prouve pas qu’il s’est rendu à la boîte de
réception.

1. Demandez au destinataire de regarder dans ses courriels indésirables.
2. Si vous utilisez votre propre fournisseur de courriel, cherchez le message dans ses journaux.
3. Ouvrez l’onglet **Livraison** du formulaire et assurez-vous que cette adresse s’y trouve.
4. Ouvrez **Destinataires** et regardez cette adresse. Un destinataire **En attente**, **Désactivé** ou **Supprimé**
   ne reçoit rien. Une adresse supprimée a habituellement rebondi ou marqué un message comme indésirable.

### Seulement certaines personnes l’ont reçu

Un destinataire avec une condition reçoit seulement les réponses qui y correspondent. Comparez la condition, dans
l’onglet **Livraison**, avec les réponses reçues. Si une condition ne laisse personne à qui envoyer, la réponse est
conservée et aucun courriel ne part, sans que ce soit compté comme un échec.

### Réessayer une livraison

Corrigez d’abord la cause, car la plupart des échecs se répètent autrement. Ouvrez ensuite la réponse sous
**Soumissions** et choisissez **Réessayer l’envoi**. Un vrai courriel part, avec les réglages de livraison actuels
du formulaire, et la réponse ne change pas.

| Code | Ce que ça veut dire |
| --- | --- |
| `DELIVERY_NOT_RETRYABLE` | Cet envoi ne peut pas être relancé pour le moment, par exemple parce qu’il a déjà été livré |
| `DELIVERY_ATTEMPT_IN_PROGRESS` | Une tentative est en cours. Attendez son résultat |
| `QUEUE_FAILED` | Le nouvel essai n’a pas pu être mis en file d’attente. Réessayez sous peu |

Un envoi marqué `EMAIL_CEILING_REACHED` a été arrêté parce que le compte a atteint son plafond mensuel
de courriels envoyés par Formerie. La réponse est conservée. Relancez-le à partir du 1er du mois suivant,
ou [écrivez-nous](https://formerie.com/fr/contact/) s’il vous en faut plus d’ici là.

### Un courriel de test ne part pas

| Code | Cause | Solution |
| --- | --- | --- |
| `FORM_DELIVERY_TEST_NOT_READY` | Un expéditeur ou un destinataire n’est pas prêt, ou le formulaire n’a aucun destinataire | Suivez les éléments sous **État de préparation de la livraison** |
| `FORM_DELIVERY_TEST_NO_RECIPIENTS` | Les réponses d’exemple ne correspondent à aucun destinataire | Changez les réponses d’exemple sous **Aperçu**, ou revoyez les conditions des destinataires |
| `FORM_DELIVERY_TEST_RATE_LIMITED` | Vous pouvez envoyer un test par minute | Patientez une minute |
| `FORM_DELIVERY_TEST_SEND_FAILED` | Le fournisseur l’a refusé | Vérifiez l’expéditeur et le fournisseur, puis réessayez |

## Une soumission a été refusée

**Symptôme :** le visiteur voit une erreur, ou votre code obtient `ok: false`.

**Comment vérifier :** une soumission refusée n’est pas conservée, donc elle n’apparaît jamais sous **Soumissions**.
Lisez plutôt le code dans la réponse, dans le panneau réseau de votre navigateur ou dans `result.error.code` avec
le SDK. Il ressemble à ceci :

```json
{
  "ok": false,
  "error": {
    "code": "SPAM_REJECTED",
    "message": "The submission was rejected."
  }
}
```

Le serveur fait ses vérifications dans l’ordre et s’arrête à la première qui échoue : origine, disponibilité, limite
de débit des routes publiques, fenêtre de réponse, taille, format, envoi répété, limites de soumission, vérifications
antipourriel, vérification humaine, réponses et quota.

| Code | État HTTP | Cause | Solution |
| --- | --- | --- | --- |
| `VALIDATION_FAILED` | 422 | Une réponse a échoué à une vérification | Consultez [Les réponses refusées](#les-réponses-refusées) |
| `SPAM_REJECTED` | 403 | Une vérification antipourriel l’a bloquée | Consultez [Refusée comme pourriel](#refusée-comme-pourriel) |
| `TURNSTILE_FAILED` | 403 | La vérification humaine a échoué, peu importe le fournisseur | Consultez [La vérification a échoué](#la-vérification-a-échoué) |
| `RATE_LIMITED` | 429 | Trop de soumissions en peu de temps | Consultez [Trop de soumissions](#trop-de-soumissions) |
| `FORM_QUOTA_REACHED` | 409 | Le formulaire a atteint son **Nombre maximal de soumissions acceptées** | Augmentez-le ou videz-le sous **Limites de soumission**, dans **Paramètres** |
| `DUPLICATE_SUBMISSION` | 409 | Ce `metadata.idempotencyKey` a déjà été accepté | Traitez-le comme un succès. Consultez [Les envois répétés](#les-envois-répétés) |
| `FORM_NOT_OPEN` | 403 | La **Fenêtre de réponse** n’est pas encore ouverte | Changez la fenêtre dans l’onglet **Publication** |
| `FORM_CLOSED` | 403 | Le formulaire est fermé, ou sa fenêtre est terminée | Changez **Accès public** ou la fenêtre dans l’onglet **Publication** |
| `FORM_MAINTENANCE` | 503 | **Accès public** est sur **Maintenance** | Remettez-le sur **Public** |
| `ACCOUNT_STORAGE_HOLD` | 403 | Le compte conserve bien plus qu’une utilisation normale, donc ses formulaires ont suspendu les nouvelles soumissions | [Écrivez-nous](https://formerie.com/fr/contact/). Tout ce qui a déjà été reçu reste en sécurité |
| `FORM_NOT_FOUND` | 404 | Mauvaise adresse, ou le formulaire n’est pas publié | Consultez [Le formulaire ne s’affiche pas](#le-formulaire-ne-saffiche-pas) |
| `FORBIDDEN_ORIGIN` | 403 | Le site du navigateur n’est pas une origine autorisée | Consultez [Une erreur CORS ou d’origine](#une-erreur-cors-ou-dorigine) |
| `BAD_REQUEST` | 400 ou 413 | Le corps n’a pas d’objet `fields`, ou dépasse 100 000 octets | Envoyez `{ "fields": { ... } }` et raccourcissez les longues réponses |
| `INVALID_JSON` | 400 | Le corps n’est pas du JSON valide | Corrigez ce que votre code envoie |
| `QUEUE_FAILED` | 503 | Le courriel n’a pas pu être mis en file d’attente | Demandez au visiteur de réessayer sous peu |
| `INTERNAL_ERROR` | 500 | Quelque chose s’est mal passé de notre côté | Réessayez sous peu |

### Les réponses refusées

`VALIDATION_FAILED` énumère chaque problème dans `error.fields` et `error.issues`, avec un chemin, un code et un message :

```json
{
  "ok": false,
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "The submitted form contains invalid fields.",
    "fields": {
      "contact.email": [
        {
          "path": "contact.email",
          "code": "FIELD_EMAIL_INVALID",
          "message": "Invalid email address.",
          "rule": "email",
          "params": {}
        }
      ]
    },
    "issues": [
      {
        "path": "contact.email",
        "code": "FIELD_EMAIL_INVALID",
        "message": "Invalid email address.",
        "rule": "email",
        "params": {}
      }
    ]
  }
}
```

Affichez chaque message à côté de son champ. Les pages hébergées et les intégrations le font pour vous. Les codes sont
présentés par type de champ dans la [Référence de la définition de formulaire](/fr/guides/form-reference/), et vos propres
validateurs renvoient le `code` que vous leur avez donné.

Un champ obligatoire mais masqué ne peut pas échouer, parce que le serveur ignore les champs masqués. Si un champ
obligatoire échoue sans arrêt, vérifiez que votre interface l’envoie sous son nom exact, avec les groupes sous forme
d’objets imbriqués.

### Refusée comme pourriel

La réponse ne dit pas quelle vérification l’a bloquée. Passez donc les trois en revue sous **Paramètres**, dans
**Antipourriel** :

| Vérification | Ce qui la déclenche | Solution |
| --- | --- | --- |
| Champ caché | Le champ caché a une valeur. Les nouveaux formulaires utilisent `_formerie_hp` | Dans votre interface, omettez ce champ ou laissez-le vide |
| **Délai minimal de soumission** | `metadata.startedAt` est plus récent que la limite, 1 seconde sur les nouveaux formulaires | Fixez `startedAt` à l’affichage du formulaire, pas à l’envoi, ou baissez la limite |
| **Nombre maximal de liens** | Plus de liens que la limite dans l’ensemble des réponses, 3 sur les nouveaux formulaires. Les adresses Web des champs `url` comptent aussi | Augmentez la limite. `0` refuse tout lien, et un réglage vide désactive la vérification |

### Trop de soumissions

`RATE_LIMITED` vient de l’un de ces deux endroits :

- **Limites de soumission**, sous **Paramètres**. Les nouveaux formulaires permettent 10 soumissions par visiteur toutes
  les 10 minutes, et 300 pour tout le formulaire chaque heure. Augmentez-les si votre formulaire connaît de vrais pics, jusqu’à 1 000 par heure pour un formulaire du forfait gratuit.
  Les gens d’un même réseau, comme un bureau, partagent la limite par visiteur.
- Une limite à court terme sur les routes publiques, que vous ne pouvez pas changer. Elle envoie `Retry-After`, en secondes.

Dites au visiteur de patienter, et gardez ses réponses à l’écran.

### Les envois répétés

`DUPLICATE_SUBMISSION` veut dire que le premier envoi a fonctionné : c’est une bonne nouvelle. Affichez votre message de
réussite. Envoyez un nouveau `metadata.idempotencyKey` pour chaque nouvelle soumission, et réutilisez une clé seulement pour
réessayer la même soumission.

## Le formulaire ne s’affiche pas

**Symptôme :** le lien affiche une erreur, ou la page où vous avez intégré le formulaire est vide.

**Comment vérifier :** ouvrez l’**URL hébergée** du formulaire dans une fenêtre privée. Si elle fonctionne, le formulaire est
correct et le problème vient de la page autour. Si vous voyez une ligne de JSON, lisez son `code`.

| Ce que vous voyez | Cause | Solution |
| --- | --- | --- |
| `FORM_NOT_FOUND` | Le formulaire n’a jamais été publié, **Accès public** est sur **Non publié**, ou l’adresse est mauvaise | Publiez dans l’onglet **Publication**, et copiez l’adresse à partir de là |
| `FORM_CLOSED`, `FORM_NOT_OPEN` | Le formulaire est fermé, ou en dehors de sa **Fenêtre de réponse** | Changez-les dans l’onglet **Publication** |
| `FORM_MAINTENANCE` | **Accès public** est sur **Maintenance** | Remettez-le sur **Public** |
| `FORM_NOT_FOUND` sur votre propre nom d’hôte | Le nom d’hôte n’est pas actif ou n’est pas connecté à ce formulaire | Terminez les étapes DNS sous **Domaines** et vérifiez sa connexion |
| « The form could not be loaded. » ou « Loading form... » | Le navigateur n’a pas pu charger le script du formulaire | Cherchez une requête bloquée vers `cdn.formerie.com` dans le panneau réseau du navigateur |
| Une ancienne version du formulaire | Vos changements sont encore un brouillon | Choisissez **Publier les modifications** |
| Une question manque | Une condition la masque, ou elle se trouve à une étape suivante | Revoyez **Conditions** et **Parcours** |

### Une intégration n’affiche rien

- Le script ajoute son iframe à l’endroit exact de la balise. Avec `data-formerie-target`, le sélecteur doit correspondre à un
  élément de la page au moment où le script s’exécute.
- `data-formerie-form` doit être `identifiant-espace/identifiant-formulaire`, comme dans le **Code d’intégration**. Une mauvaise
  valeur affiche `FORM_NOT_FOUND` dans l’iframe.
- Si votre site définit une politique de sécurité du contenu (CSP), autorisez `https://forms.formerie.com` comme source de cadre et
  de script, et `https://cdn.formerie.com` comme source de script.

### Un montage dans le navigateur n’affiche rien

Le montage dans le navigateur charge le formulaire avec un appel à partir de votre page. Sans l’adresse de votre site dans les
origines autorisées, cet appel échoue. Consultez la prochaine section.

## Une erreur CORS ou d’origine

**Symptôme :** la console de votre navigateur affiche `blocked by CORS policy`, votre code obtient une erreur réseau comme
`Failed to fetch` ou le `NETWORK_ERROR` du SDK, et la requête apparaît en 403 ou 404 dans le panneau réseau. Votre code ne peut pas lire de code Formerie, parce
qu’une requête de navigateur refusée revient sans les en-têtes qui le permettraient.

**Comment vérifier :** cela arrive seulement quand le code du navigateur sur votre site appelle Formerie, c’est-à-dire avec le
montage dans le navigateur, un paquet de framework utilisé dans le navigateur ou votre propre `fetch`. Un lien hébergé et une
intégration par script n’appellent rien à partir de votre site, donc ils ne peuvent pas la causer.

Ouvrez la requête en échec dans le panneau réseau. C’est souvent la requête `OPTIONS`, et sa réponse indique `FORBIDDEN_ORIGIN` ou
`FORM_NOT_FOUND`. Comparez l’en-tête `Origin` de la requête avec votre liste.

| Cause | Solution |
| --- | --- |
| Votre site n’est pas dans la liste | Ajoutez-le sous **Adresses de vos sites** dans l’onglet **Publication**, ou **Origines autorisées** dans **Paramètres**, puis publiez |
| Vous l’avez ajouté sans publier | Les origines s’appliquent à la publication. **Publier** les enregistre pour vous |
| L’adresse diffère légèrement | La correspondance est exacte. `https://example.com`, `https://www.example.com` et `http://example.com` sont trois entrées : ajoutez chacune de celles où votre site répond |
| Vous testez en local | Ajoutez votre adresse de développement avec son port, comme `http://localhost:5173` |
| Vous avez utilisé un chemin ou un caractère générique | Indiquez seulement l’adresse. Les chemins échouent avec `FORM_CONFIG_ORIGIN_INVALID`, et `*` avec `FORM_CONFIG_ORIGIN_WILDCARD` |
| La réponse indique `FORM_NOT_FOUND` | L’identifiant de l’espace ou du formulaire est mauvais, ou le formulaire n’est pas publié. L’erreur ressemble à du CORS parce que sans formulaire, il n’y a aucune liste d’origines à autoriser |
| Vous avez ajouté votre propre en-tête de requête | Les navigateurs peuvent seulement envoyer `Content-Type` ici. Retirez l’en-tête, ou envoyez-le à partir de votre serveur |

Le code sur votre propre serveur n’a besoin de rien de tout ça, sauf s’il transmet un en-tête `Origin`. Sans cet en-tête, la vérification ne s’applique
pas. Consultez [Origines autorisées](/fr/guides/spam-protection/#origines-autorisées).

## La vérification a échoué

**Symptôme :** une soumission renvoie `TURNSTILE_FAILED`. C’est le même code pour Cloudflare Turnstile et pour reCAPTCHA, et la réponse
ne donne pas de raison.

**Comment vérifier :** regardez les réglages de **Vérification humaine** du formulaire sous **Paramètres**, puis passez ces causes en revue.

| Cause | Solution |
| --- | --- |
| Aucun jeton n’a été envoyé | Votre interface doit transmettre le jeton du fournisseur dans `verificationToken`. Les pages hébergées, les intégrations et le montage dans le navigateur s’en occupent pour vous |
| Le jeton a déjà servi ou est expiré | Un jeton fonctionne une seule fois. Obtenez-en un nouveau à chaque tentative, y compris après un envoi refusé |
| Le domaine du widget ne correspond pas | Formerie vérifie que le jeton vient du site qui fait la requête. Consultez la prochaine section |
| **Géré par Formerie** sur votre propre site | Les clés gérées fonctionnent sur les domaines Formerie pris en charge. Utilisez vos propres clés pour votre domaine |
| Mauvaises clés | La clé de site et la clé secrète doivent venir du même widget. Enregistrez-les de nouveau sous **Vérification humaine** |
| **Action attendue** différente | Elle doit correspondre à l’action envoyée par votre widget |
| Score reCAPTCHA v3 trop bas | Baissez le **Score minimal**, de 0 à 1 |

### Quel domaine ajouter à votre widget

Avec vos propres clés, la console du fournisseur énumère les domaines où votre widget fonctionne. Ajoutez le domaine où le widget se charge :

| Votre méthode de publication | Domaine à ajouter |
| --- | --- |
| Lien hébergé | `forms.formerie.com`, ou votre propre nom d’hôte connecté |
| Intégration par script | `forms.formerie.com`, ou votre propre nom d’hôte connecté, parce que le widget s’exécute dans l’iframe |
| Montage dans le navigateur ou votre propre interface | Votre propre site |

### La vérification en passant par votre serveur

Un jeton obtenu sur votre page et transmis par votre propre serveur peut échouer à la vérification du domaine. Sans en-tête `Origin`, Formerie
compare le domaine du jeton avec le sien. Pour que ça passe, transmettez l’en-tête `Origin` du visiteur avec la requête, et ajoutez aussi ce site aux
origines autorisées.
