Référence des erreurs
Catalogue exhaustif des codes d'erreur retournés par l'API B2B, groupés par domaine fonctionnel.
Les descriptions ci-dessous utilisent l'écriture inclusive (point médian) pour les références à des personnes (employé·e, votant·e, candidat·e). Les messages effectivement renvoyés par l'API sont actuellement inclusifs pour le domaine Employe (à parité avec le code source) ; les autres domaines sont en cours d'harmonisation côté serveur. Si vous matchez sur le contenu textuel d'un message, préférez le code d'erreur (colonne Code) qui est stable.
Format
Toutes les erreurs suivent le pattern ErrorOr<T> côté SDK. Format JSON (RFC 7807 ProblemDetails) côté HTTP :
{
"type": "Emploi.NotFound",
"title": "L'emploi n'existe pas.",
"status": 404,
"detail": "...",
"errors": { }
}
Côté SDK, utilisez :
if (result.IsError)
{
var err = result.FirstError;
var status = err.Metadata.GetValueOrDefault("StatusCode"); // int
var url = err.Metadata.GetValueOrDefault("Url"); // string
var body = err.Metadata.GetValueOrDefault("RawBody"); // string JSON
// err.Code, err.Description, err.Errors (validation)
}
Voir ApiError.ClientError.
Mapping des types Error → HTTP
Appliqué par B2BController.Problem :
Type Error | Code HTTP |
|---|---|
Error.Validation | 400 Bad Request |
Error.NotFound | 404 Not Found |
Error.Conflict | 409 Conflict |
Error.Failure | 500 Internal Server Error |
| Autre | 500 par défaut |
Également :
401 Unauthorized— clé API manquante/invalide (voir authentication.md)403 Forbidden— module requis (MaCarteDeMembre/Votez) non activé sur le client
Résumé quantitatif
168 codes d'erreur distincts répartis ainsi :
| HTTP | Type | Nombre |
|---|---|---|
| 400 | Validation | 115 (68.5 %) |
| 404 | NotFound | 35 (20.8 %) |
| 409 | Conflict | 14 (8.3 %) |
| 500 | Failure | 3 (1.8 %) |
| 403 | Forbidden | 1 (0.6 %) |
Par domaine : Formulaire 20 · Employé/Emploi 20 · Question/Vote 24 · Champ utilisateur 14 · Campagne 15 · Votant 11 · Demande d'adhésion 9 · Employeur/Syndicat 11 · Adhésion 6 · Courriel 4 · Objet consentement 2.
Employé et synchronisation
| Code | HTTP | Description | Produit par |
|---|---|---|---|
Employe.PrenomRequis | 400 | Le prénom est requis. | AddEmploye, validateurs Sync |
Employe.NomRequis | 400 | Le nom est requis. | AddEmploye, validateurs Sync |
Employe.CourrielRequis | 400 | Le courriel est requis. | AddEmploye, validateurs Sync |
Employe.DateSignatureAdhesionInvalide | 500 | La date de signature de l'adhésion est invalide. | Sync |
Employe.NotFound | 404 | L'employé·e n'existe pas. | DeleteEmploye, UpdateEmploye, EnvoyerFormulaires |
Employe.EmployeurMustExist | 404 | L'employeur n'existe pas. | Sync |
Employe.CourrielExists | 409 | Un·e employé·e avec le courriel existe déjà. | AddEmploye, Sync |
Employe.Existing | 409 | Un·e employé·e avec cet identifiant externe existe déjà. | AddEmploye |
Employe.ChampUtilisateurInexistant | 404 | Le champ utilisateur n'existe pas. | Validation champ |
Employe.Courriel | 400 | Les courriels ne peuvent pas être identiques. | Update employé·e |
Employe.CourrielDejaValide | 400 | Le courriel est déjà valide. | Validation courriel |
Employe.InvalidData | 400 | Les données de l'employé·e sont invalides. | EmployeSynchronizerV2 |
Emploi
| Code | HTTP | Description | Produit par |
|---|---|---|---|
Emploi.NotFound | 404 | L'emploi n'existe pas. | Queries emploi |
Emploi.NotFoundByIdExterne | 404 | L'emploi n'existe pas. | UpdateEmploi, DeleteEmploi, courriels |
Emploi.NotFoundByIdUnique | 404 | L'emploi n'existe pas. | Queries emploi |
Emploi.DejaExistant | 409 | Un emploi existe déjà pour cet·te employé·e chez cet employeur. | AddEmploi |
Emploi.IdExterneDejaUtilise | 409 | Un emploi avec l'identifiant externe existe déjà. | AddEmploi |
Emploi.DateFinAvantDateDebut | 400 | La date de fin ne peut pas être antérieure à la date de début. | AddEmploi, UpdateEmploi |
Emploi.EmployeurImmutable | 400 | L'employeur ne peut pas être modifié. Créez un nouvel emploi pour un employeur différent. | UpdateEmploi |
Emploi.EmployeImmutable | 400 | L'employé·e ne peut pas être modifié·e. | UpdateEmploi |
Employeur et syndicat
Employeur
| Code | HTTP | Description | Produit par |
|---|---|---|---|
Employeur.NotFound | 404 | L'employeur n'existe pas. | UpdateEmployeur, DeleteEmployeur, AddEmploi |
Employeur.Existing | 409 | L'employeur existe déjà. | AddEmployeur |
Employeur.NomDuplique | 409 | Un employeur avec le nom existe déjà. | AddEmployeur, UpdateEmployeur |
Employeur.NomRequis | 400 | Le nom de l'employeur est requis. | Validateurs employeur |
Syndicat
| Code | HTTP | Description | Produit par |
|---|---|---|---|
Syndicat.NotFound | 404 | Le syndicat n'existe pas. | Queries syndicat |
Syndicat.NomDejaUtilise | 409 | Un syndicat avec le nom existe déjà. | Commandes syndicat |
Syndicat.IdExterneDejaUtilise | 409 | Un syndicat avec l'identifiant externe existe déjà. | Commandes syndicat |
Syndicat.NomRequis | 400 | Le nom du syndicat est requis. | Validateurs syndicat |
Syndicat.HasEmployeurs | 400 | Le syndicat ne peut pas être supprimé car il contient des employeurs. | DeleteSyndicat |
Syndicat.HasAdhesions | 400 | Le syndicat ne peut pas être supprimé car il contient des adhésions. | DeleteSyndicat |
Syndicat.AucunSyndicatPourClient | 404 | Aucun syndicat n'est configuré pour ce client. | Init syndicat |
Adhésion
| Code | HTTP | Description | Produit par |
|---|---|---|---|
Adhesion.NotFound | 404 | L'adhésion n'existe pas. | Queries adhésion |
Adhesion.ForEmployeNotFound | 404 | L'adhésion pour l'employé·e n'existe pas. | Queries adhésion |
Adhesion.InvalidState | 400 | L'adhésion est dans un état invalide. | Opérations adhésion |
Adhesion.LinkedToActiveCampaign | 409 | Impossible de supprimer une adhésion liée à un·e votant·e dans une campagne active. | DeleteAdhesion* |
Adhesion.HasPayments | 409 | Impossible de supprimer une adhésion liée à un paiement. | DeleteAdhesion* |
Adhesion.HasPaymentAuthorizations | 409 | Impossible de supprimer une adhésion liée à une autorisation de paiement. | DeleteAdhesion* |
Demande d'adhésion (conciliation)
| Code | HTTP | Description | Produit par |
|---|---|---|---|
DemandeAdhesion.NotFound | 404 | La demande d'adhésion n'existe pas. | Rejeter, Confirmer |
DemandeAdhesion.EmployeurInexistant | 404 | L'employeur n'existe pas. | Queries demande |
DemandeAdhesion.StatutInvalidePourAccepter | 409 | Le statut de la demande d'adhésion est invalide pour accepter. | Confirmer |
DemandeAdhesion.StatutInvalidePourRejet | 409 | Le statut de la demande d'adhésion est invalide pour un rejet. | Rejeter |
DemandeAdhesion.StatutInvalidePourFusion | 409 | Le statut est invalide pour fusionner. | Commandes fusion |
DemandeAdhesion.StatutInvalidePourModification | 409 | Le statut est invalide pour une modification. | Commandes modif |
DemandeAdhesion.StatutInvalidePourRemiseEnAttente | 409 | Le statut est invalide pour une remise en attente. | Commandes remise en attente |
DemandeAdhesion.AcceptationInterditeSansSupportAdhesionPublique | 409 | Le système de mission du client ne prend pas en charge l'adhésion publique. | Acceptation |
DemandeAdhesion.ConfirmationInterditeSansSystemeDeMissionActif | 409 | La confirmation requiert que le système de mission soit activé. | Confirmer |
Voir le flux complet dans guides/employee-sync.md §5.
Courriel
| Code | HTTP | Description | Produit par |
|---|---|---|---|
Courriel.BadEmailAddress | 400 | Le courriel est mal formé ou invalide. | Validateurs courriel |
Courriel.NotAssociatedWithEmployee | 400 | Le courriel n'est ni le courriel principal ni le courriel alternatif de l'employé·e. | EnvoyerFormulaire, EnvoyerDerniereCarteMembre |
Courriel.RateLimitExceeded | 500 | Trop de courriels envoyés. Veuillez réessayer plus tard. | EnvoyerCourrielTransactionnel |
Courriel.ContentTooLarge | 400 | Le contenu du courriel ne peut pas dépasser la limite. | Service courriel |
Campagne (module Votez)
| Code | HTTP | Description | Produit par |
|---|---|---|---|
Campagne.NotFound | 404 | La campagne est introuvable. | UpdateCampagne, PublierCampagne, DeleteCampagne |
Campagne.NotFoundBySlug | 404 | La campagne est introuvable. | Queries slug |
Campagne.TransitionNonPermise | 400 | Transition d'état non permise. | Transitions d'état |
Campagne.DejaArchive | 400 | La campagne est déjà archivée. | Opérations campagne |
Campagne.AucuneQuestion | 400 | La campagne doit avoir au moins une question. | PublierCampagne |
Campagne.VoteNonOuvert | 400 | Le vote n'est pas ouvert. | Opérations vote |
Campagne.VoteTermine | 400 | Le vote est terminé. L'envoi de masse n'est plus permis. | Envoi de masse |
Campagne.OuvertureVoteApresFermeture | 400 | L'ouverture du vote doit précéder la fermeture. | Planification |
Campagne.SlugDejaUtilise | 409 | Le slug est déjà utilisé. | AddCampagne |
Campagne.VotantsOntVote | 409 | Impossible de supprimer les votant·e·s car certain·e·s ont déjà voté. | Suppression votant·e·s |
Campagne.ResetNonPermis | 400 | La réinitialisation n'est pas permise pour une campagne archivée. | Reset |
Campagne.SimulationFeatureDisabled | 403 | Les actions de débogage sont désactivées pour ce client. | Opérations debug |
Campagne.DepublierAvecVotes | 400 | Impossible de dépublier la campagne car des votes ont été enregistrés. | DepublierCampagne |
Campagne.SupprimerAvecVotes | 409 | Impossible de supprimer la campagne car des votes ont été enregistrés. | DeleteCampagne |
Campagne.NomDejaUtilise | 409 | Une campagne avec le nom interne existe déjà. | AddCampagne |
Question, option, vote
| Code | HTTP | Description | Produit par |
|---|---|---|---|
Question.NotFound | 404 | La question est introuvable. | Queries question |
Question.AbstentionNonPermise | 400 | L'abstention n'est pas permise pour cette question. | Validation vote |
Question.AbstentionAvecReponses | 400 | L'abstention ne peut pas être combinée avec des réponses. | Validation vote |
Question.TropPeuDeReponses | 400 | Le nombre de réponses est insuffisant. | Validation vote |
Question.TropDeReponses | 400 | Le nombre maximum de réponses est dépassé. | Validation vote |
Question.ReponseInvalide | 400 | Une réponse sélectionnée est invalide. | Validation vote |
Question.DejaRepondu | 400 | Cette question a déjà été répondue. | Validation vote |
Question.MinReponsesNegatif | 400 | Le minimum de réponses ne peut pas être négatif. | Création question |
Question.MaxReponsesTropBas | 400 | Le maximum de réponses doit être au moins 1. | Création question |
Question.MinSuperieurMax | 400 | Le minimum de réponses ne peut pas être supérieur au maximum. | Création question |
Question.OptionTexteRequis | 400 | Le texte est requis pour l'option. | AddOption |
Question.OptionCandidatRequis | 400 | Le·la candidat·e est requis·e pour l'option. | AddOption |
Question.CandidatIntrouvable | 404 | Le·la candidat·e est introuvable. | AddOption |
Question.TypeQuestionIncompatible | 400 | Le type d'option ne correspond pas au type de question. | AddOption |
Question.OptionTexteVide | 400 | Le texte de l'option ne peut pas être vide. | Validation option |
Question.CandidatIdVide | 400 | L'identifiant du·de la candidat·e ne peut pas être vide. | Validation option |
Question.OptionIntrouvable | 404 | L'option de réponse est introuvable. | Queries option |
Question.ADesVotes | 409 | La question ne peut pas être supprimée car elle a des votes. | DeleteQuestion |
Question.OrdreIdsDupliques | 400 | La liste de réordonnancement contient des identifiants en double. | ReorderQuestions |
Question.OrdreIdsManquants | 400 | La liste de réordonnancement doit contenir tous les identifiants de questions. | ReorderQuestions |
Question.QuestionObligatoireManquante | 400 | Une réponse est requise pour cette question obligatoire. | Validation vote |
Question.ModificationRestrictionsInterdite | 400 | Les restrictions ne peuvent pas être modifiées lorsque le vote est ouvert. | UpdateQuestion |
Question.PosteRequisPourElection | 400 | Un poste est requis pour une question de type élection. | Création question |
Question.NomDejaUtilise | 409 | Une question avec ce nom existe déjà dans cette campagne. | Création question |
Votant et liste électorale
| Code | HTTP | Description | Produit par |
|---|---|---|---|
Votant.NotFound | 404 | Le·la votant·e est introuvable. | Queries votant |
Votant.CodeAccesNotFound | 404 | Aucun·e votant·e n'a été trouvé·e avec ce code d'accès. | Validation code d'accès |
Votant.EstRadie | 400 | Le·la votant·e est radié·e. | Autorisation vote |
Votant.PasDeDroitDeVote | 400 | Le·la votant·e n'a pas le droit de vote. | Autorisation vote |
Votant.DejaRadie | 400 | Le·la votant·e est déjà radié·e. | RadierVotant |
Votant.CourrielDejaUtilise | 409 | Ce courriel est déjà utilisé pour cette campagne. | UpsertVotant |
Votant.CourrielAlternatifDejaUtilise | 409 | Ce courriel alternatif est déjà utilisé pour cette campagne. | UpsertVotant |
Votant.IdentifiantDejaUtilise | 409 | Cet identifiant est déjà utilisé pour cette campagne. | UpsertVotant |
Votant.ADesVotes | 400 | Le·la votant·e a déjà voté et ne peut pas être supprimé·e. | DeleteVotant |
Votant.ADejaVote | 400 | Le·la votant·e a déjà voté et ne peut pas être modifié·e. | UpsertVotant |
Votant.CodeAccesGenerationFailed | 500 | Impossible de générer un code d'accès unique après plusieurs tentatives. | Création votant·e |
Champs utilisateur
| Code | HTTP | Description | Produit par |
|---|---|---|---|
ChampUtilisateur.NotFound | 404 | Champ utilisateur introuvable. | UpdateChampUtilisateur, DeleteChampUtilisateur |
ChampUtilisateur.NomExiste | 400 | Le nom existe déjà. | AddChampUtilisateur |
ChampUtilisateur.EmployeurIntrouvable | 400 | Employeur introuvable. | Assignation |
ChampUtilisateur.EmployeursIntrouvables | 400 | Employeurs introuvables. | SetEmployeurs |
ChampUtilisateur.PasTypeChoix | 409 | Le champ utilisateur n'est pas de type choix. | Update choix |
ChampUtilisateur.ChoixExiste | 400 | Le choix existe déjà pour ce champ utilisateur. | Création choix |
ChampUtilisateur.ChoixInvalide | 400 | La valeur n'est pas un choix valide pour le champ. | Validation champ |
ChampUtilisateur.InUse | 400 | Le champ utilisateur est utilisé par un ou plusieurs choix. | Suppression |
ChampUtilisateur.ChoixNotFound | 404 | Choix introuvable pour le champ. | Queries choix |
ChampUtilisateur.BoolInvalide | 400 | La valeur n'est pas un booléen valide pour le champ. | Validation champ |
ChampUtilisateur.MaxLengthTropGrand | 400 | La longueur maximale ne peut pas dépasser la limite. | Création |
ChampUtilisateur.DateInvalide | 400 | La date est invalide pour le champ. | Validation champ |
ChampUtilisateur.TypeChampInvalide | 400 | Le type de champ est invalide. | Update |
ChampUtilisateur.Introuvable | 400 | Un ou plusieurs champs utilisateurs sont introuvables. | Validation |
Formulaire
| Code | HTTP | Description | Produit par |
|---|---|---|---|
Formulaire.NotFound | 404 | Le formulaire n'existe pas. | Queries formulaire |
Formulaire.TemplateEmpty | 400 | Le formulaire n'a pas de template de courriel pour le lien. | Envoi courriel |
Formulaire.NomRequis | 400 | Le nom du formulaire est requis. | Validateurs |
Formulaire.RouteRequise | 400 | La route du formulaire est requise. | Validateurs |
Formulaire.CouleurPrincipaleRequise | 400 | La couleur principale est requise. | Validateurs |
Formulaire.CouleurSecondaireRequise | 400 | La couleur secondaire est requise. | Validateurs |
Formulaire.TitreSectionRequis | 400 | Le titre de la section est requis. | Validateurs |
Formulaire.RemerciementRequis | 400 | Le message de remerciement est requis. | Validateurs |
Formulaire.PaiementRequiertVerifEtAdhesion | 400 | Le paiement nécessite les sections Vérification et Adhésion. | Validateurs |
Formulaire.MontantPaiementRequis | 400 | Un montant de paiement supérieur à zéro est requis. | Validateurs |
Formulaire.TemplateCourrielIncoherent | 400 | Le sujet et le message doivent être tous deux fournis ou vides. | Validateurs |
Formulaire.CourrielSoumissionRequis | 400 | Le sujet et le message du courriel de confirmation sont requis. | Validateurs |
Formulaire.SectionRequisePourFormulairePublic | 400 | La section ne peut pas être désactivée sur un formulaire public. | Validateurs |
Formulaire.SectionRequisePourPaiement | 400 | La section est requise tant que le paiement est activé. | Validateurs |
Formulaire.DemissionRequiertAdhesion | 400 | La section Démission nécessite la section Adhésion. | Validateurs |
Formulaire.AdhesionRequisePourDemission | 400 | La section Adhésion ne peut pas être désactivée si Démission est active. | Validateurs |
Formulaire.DoitEtrePersonnalise | 400 | Le formulaire doit être de type personnalisé pour être envoyé par courriel. | Envoi courriel |
Formulaire.RouteAlreadyExists | 400 | Un formulaire avec cette route existe déjà. | Création |
Formulaire.ChampsUtilisateursReservesAuxGeneriques | 400 | Les champs utilisateurs ne peuvent être configurés que sur formulaire générique. | Validateurs |
Formulaire.ProprieteMembreIntrouvable | 400 | Une ou plusieurs propriétés de membre n'existent pas pour ce client. | Validateurs |
Objet de consentement
| Code | HTTP | Description | Produit par |
|---|---|---|---|
ObjetConsentement.NotFound | 404 | L'objet de consentement n'existe pas. | Queries |
ObjetConsentement.Existing | 409 | L'objet de consentement existe déjà. | Création |
Erreurs transverses du SDK
Erreurs générées par le SDK lui-même (pas par le serveur) :
| Code | HTTP/Source | Description |
|---|---|---|
MCM.CantReachApi | Erreur réseau locale | Impossible de joindre MCM (timeout, DNS, TLS) |
MCM.Deserialize | Réponse non parseable | JSON reçu mais incompréhensible par le SDK (mise à jour SDK requise) |
MCM.ClientError.{statusCode} | Tout code 4xx/5xx non typé par le serveur | Erreur HTTP brute quand le body n'est pas un ProblemDetails standard |
Chaque erreur porte les métadonnées StatusCode, StatusName, Url, RawBody — voir ApiError.cs.
Erreurs de validation FluentValidation
La majorité des codes 400 Validation proviennent de validateurs FluentValidation dans les handlers. Quand plusieurs règles échouent, toutes les erreurs sont accumulées dans la réponse :
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Prenom": ["Le prénom est requis."],
"Courriel": ["Le courriel est mal formé ou invalide."]
}
}
Côté SDK, vous retrouvez les champs dans Error.Metadata["RawBody"] ou en parsant directement si vous gérez la réponse HTTP.
Clés de métadonnées courantes
Certaines erreurs incluent des métadonnées pour donner du contexte :
| Code | Clés de métadonnées |
|---|---|
Emploi.NotFound | idExterne |
Employe.NotFound | id, idExterne, idUnique |
ChampUtilisateur.NotFound | id, nom |
Votant.CourrielDejaUtilise | courriel |
Campagne.SlugDejaUtilise | slug |
Question.TropPeuDeReponses | min |
Question.TropDeReponses | max |
Syndicat.HasEmployeurs | count |
Syndicat.HasAdhesions | count |
Gestion recommandée
var result = await employesClient.AddEmploye(dto);
if (result.IsError)
{
var err = result.FirstError;
switch (err.Code)
{
case "Employe.Existing":
case "Employe.CourrielExists":
// Dédup de votre côté — lire l'existant
break;
case "Employe.EmployeurMustExist":
// Créer l'employeur manquant puis relancer
break;
case string c when c.StartsWith("MCM.ClientError.5"):
case "MCM.CantReachApi":
// Erreur transitoire — retry avec backoff
break;
default:
// Log + alerte
logger.LogError("B2B {Code}: {Msg}", err.Code, err.Description);
break;
}
}
Voir idempotency.md §2 pour la stratégie complète de retry.
Notes d'implémentation
-
Isolation par client : toutes les queries filtrent par
ClientId(injecté depuis la clé API) pour garantir le cloisonnement multi-locataire. UnNotFoundpeut donc masquer un contrôle d'autorisation (la ressource existe pour un autre client). -
Sync partiel :
ISyncClient.Syncne retourne pas d'erreur globale pour les échecs individuels. InspectezB2BSyncResult.Erreurspar entité. -
Transitions d'état : les demandes d'adhésion ont une machine à états ; certaines transitions ne sont valides que depuis un statut précis (
ATransferer→Confirmee, etc.). -
Suppression bloquée : de nombreux endpoints
Delete*retournent409 Conflictsi des enfants actifs existent. Nettoyer d'abord les enfants. -
Unicité : les
*DejaUtilisereflètent des contraintes d'unicité côté DB. Ne reposez pas dessus pour de la déduplication de votre côté — vérifiez avant création quand possible.
Voir aussi
- Getting Started — intro au pattern
ErrorOr<T> - Guide — idempotence et retry — stratégies par code
- Authentification — erreurs
401/403 - Référence HTTP — mapping statut ↔ endpoint