Tu lances Codex comme d’habitude. Même compte, même repo, même commande. Et là, boum : « model is not supported ». Le pire, c’est le côté injuste : hier ça passait, et tu n’as rien déployé.
Si Codex est dans ton produit (ou pire, dans une brique critique comme un agent de refacto, un générateur de PR, un pipeline d’analyse), tu ne peux pas traiter ça comme un incident « outil ». Tu dois le traiter comme un risque de dépendance externe. Et la bonne nouvelle, c’est qu’on peut s’en protéger sans transformer ton codebase en centrale nucléaire.
« Model is not supported » sur Codex : les 3 causes qui reviennent vraiment
Ce message a un défaut majeur : il mélange des situations différentes. Et si tu ne sépares pas les causes, tu vas “fixer” le mauvais truc et perdre des heures.
Cause n°1 : quota, rate limit, ou comptage d’usage qui a changé. Tu penses appeler un modèle « supporté », mais ton plan ou ton usage effectif ne suit plus. Un incident côté plateforme peut aussi accélérer la consommation, ou déclencher des limites plus tôt que prévu. Résultat, ton intégration se met à échouer alors que tu n’as pas atteint tes propres seuils internes.
Cause n°2 : flag backend de support (ou retrait temporaire) sur un modèle. C’est le scénario le plus rageant. Le modèle apparaît un jour, puis disparaît, ou se met à renvoyer des erreurs selon le contexte (CLI, extension, app). Côté utilisateur, ça ressemble à une régression ou à un downgrade silencieux. Côté infra, ça ressemble à un rollout, un A/B, une désactivation partielle.
Cause n°3 : mismatch UI / CLI / extension. Typiquement, l’interface te laisse sélectionner un modèle, mais l’API ou l’outil utilisé derrière ne l’a pas (ou pas avec ton type de compte, ou pas sur ce endpoint précis). Le bug peut être aussi bête qu’un cache local, une session, un token qui ne porte pas les mêmes droits, ou une différence d’implémentation entre intégrations.
Sponsorisé par Le Scribouillard
Besoin de contenu optimisé SEO ?
Utilisez la meilleure plateforme française de création de contenu assistée par IA ! Et générez des articles pour moins de 1€ !
Ce que je fais en premier quand ça casse : isoler le “où” avant de chercher le “pourquoi”
Avant de discuter “modèle retiré” ou “incident OpenAI”, je veux une réponse claire à une question simple : ça casse où, exactement ? Dans l’app desktop ? Dans l’extension VS Code ? Dans le CLI ? Dans un backend via API ?
Parce que si ça casse uniquement dans un endroit, tu es probablement dans un problème d’auth, de session, de plan attaché au compte, ou de support différent selon l’outil. Et si ça casse partout, tu es probablement sur un retrait de support, un incident, un changement de policy, ou un quota atteint plus tôt que prévu.
Très concrètement, je reproduis sur un appel minimal, sans “vraie” charge. Pas besoin de pousser une tâche coûteuse. Je veux juste vérifier : « est-ce que ce modèle répond avec ce compte, aujourd’hui ? »
Mettre en place un healthcheck quotidien des modèles (oui, quotidien)
Si ton produit dépend d’un modèle précis, tu dois être celui qui découvre la régression, pas ton client à 9h12. Le healthcheck, c’est la base. Et non, ce n’est pas “du monitoring en plus”, c’est de la gestion de dépendance.
L’idée est simple : tu gardes une liste de modèles attendus (ou plutôt, une liste de capacités attendues), et tu exécutes un micro-appel (token budget minimal) sur un horaire fixe. Tu stockes le résultat avec le code d’erreur, le modèle, le type de compte, l’outil/endpoint utilisé, et tu alertes dès que ça diverge.
Un point important : fais ton check avec les mêmes credentials et le même chemin technique que la prod. Tester un modèle avec ton compte perso dans une UI ne prouve rien pour ton backend SaaS.
type ModelCheckResult = {
model: string;
ok: boolean;
errorCode?: string;
message?: string;
latencyMs?: number;
};
export async function codexDailyHealthcheck(models: string[]): Promise<ModelCheckResult[]> {
const results: ModelCheckResult[] = [];
for (const model of models) {
const started = Date.now();
try {
// Appel volontairement minimal : 1 prompt court, faible max_output.
// Le but : détecter "not supported", "rate_limit", "quota", etc.
await callCodex({
model,
input: "ping",
max_output_tokens: 8,
});
results.push({ model, ok: true, latencyMs: Date.now() - started });
} catch (e: any) {
results.push({
model,
ok: false,
errorCode: e?.code ?? "unknown",
message: e?.message ?? String(e),
latencyMs: Date.now() - started,
});
}
}
return results;
}Le gain est immédiat : tu vois les régressions “silencieuses” le matin même, tu peux basculer un fallback avant d’avoir une vague de tickets, et tu peux corréler avec les incidents publics de la plateforme.
Pinning : fige le modèle… mais ne te mens pas sur ce que ça te protège
Le pinning (exiger explicitement un nom de modèle) est utile. Ça évite les mauvaises surprises quand un “alias” change sous tes pieds, ou quand un modèle par défaut évolue et te change la qualité, le style, ou le coût.
Mais il faut être lucide : le pinning ne te protège pas d’un modèle qui devient indisponible ou “non supporté” pour ton plan. Il te protège surtout des changements implicites. Donc oui, pin ton modèle. Et en parallèle, prépare le monde où ce modèle n’est plus là demain matin.
Feature flags : la vraie arme, c’est de pouvoir basculer sans redéployer
Si tu dois déployer en urgence juste pour changer un nom de modèle, tu as déjà perdu. Parce que la régression arrivera à un moment où tu n’as pas envie de déployer : vendredi soir, pendant un pic, ou quand la CI est déjà en feu.
Le bon pattern, c’est un feature flag de sélection de modèle (ou mieux : un flag de “capacité”) pilotable côté serveur. Ça te permet de basculer un pourcentage d’utilisateurs, de désactiver une fonctionnalité “agent” trop fragile, ou de forcer un fallback temporaire le temps que la plateforme revienne.
Et oui, ça vaut même si tu n’as pas d’outil de feature flags sophistiqué. Un paramètre en base, une config distante, un KV store… tant que c’est modifiable sans release.
Fallback propre : modèle B, dégradation fonctionnelle, et UX honnête
Le fallback, ce n’est pas “on met un autre modèle et on espère”. En pratique, tu as trois niveaux de repli, et tu dois choisir à l’avance celui qui a du sens pour ton produit.
Repli 1 : modèle alternatif même fonctionnalité. Tu gardes l’expérience, mais tu acceptes une légère différence de qualité, de vitesse, ou de coût. C’est le meilleur cas… à condition de l’avoir testé. La plupart des équipes découvrent le jour J que “le modèle B” ne respecte pas les mêmes contraintes, ou produit un format légèrement différent, et ça casse leur parsing.
Repli 2 : dégradation de fonctionnalité. Exemple terrain : tu désactives la génération automatique de PR, mais tu gardes l’analyse et les suggestions. Ou tu gardes la complétion simple, mais tu coupes l’agent autonome qui consomme trop et déclenche des limites.
Repli 3 : mode dégradé assumé côté UX. Ça veut dire : message clair, pas une erreur brute. Tu expliques qu’une capacité est temporairement indisponible, tu proposes une action (réessayer, passer en mode manuel, exporter un prompt, etc.), et tu évites de donner l’impression que “ton app est buguée”.
type Capability = "agent" | "refactor" | "generate_tests";
function pickModelFor(capability: Capability, flags: Record<string, any>) {
// L'idée : piloter ça à distance.
// Exemple : flags.models = { agent: "gpt-5.4", refactor: "gpt-5.3-codex", fallback: "gpt-5.2" }
const primary = flags.models?.[capability];
const fallback = flags.models?.fallback;
return { primary, fallback };
}
export async function runTask(capability: Capability, input: string, flags: any) {
const { primary, fallback } = pickModelFor(capability, flags);
try {
return await callCodex({ model: primary, input });
} catch (e: any) {
if (isNotSupported(e) || isRateLimited(e) || isQuotaExceeded(e)) {
// On loggue et on bascule.
logEvent("codex_fallback", { capability, primary, fallback, code: e.code });
if (fallback) return await callCodex({ model: fallback, input });
}
throw e;
}
}Le détail qui change tout : tu mesures le fallback. Si tu ne mesures pas, tu vas “survivre” en mode dégradé pendant deux semaines sans t’en rendre compte, jusqu’à ce qu’un client te dise que la qualité a chuté.
Observabilité : loggue l’erreur, le modèle, et le coût par tâche (sinon tu voles à l’aveugle)
Sur ce genre de dépendance, l’observabilité n’est pas un luxe. C’est ce qui te permet de différencier « incident plateforme », « changement de support », « explosion de conso », « bug de notre retry ».
Au minimum, je veux voir dans mes logs applicatifs : le modèle demandé, le modèle effectivement utilisé (si fallback), le code d’erreur normalisé, la latence, et un identifiant de requête corrélé. Si tu as une notion de “tâche” (analyse, refacto, génération), loggue aussi la capacité. Parce que ce n’est pas la même gravité si c’est ta feature “nice to have” qui tombe, ou le cœur du produit.
Côté métriques, le trio que je trouve le plus utile en prod : taux d’échec par modèle, taux de fallback, et coût par tâche. Le coût est important parce qu’un “fix” de disponibilité peut faire exploser ta facture si tu bascules vers un modèle plus cher sans le voir venir.
Le piège classique : confondre « modèle retiré » et « quota explosé »
Quand tu es sous pression, tu as envie d’une explication simple. Et tu vas vite conclure : « ils ont retiré le modèle ». Parfois c’est vrai. Mais parfois tu es juste en train de payer un changement de comptage, une hausse de consommation, ou une limite atteinte plus tôt (et ça peut arriver même sur des plans payants, parce que la limite n’est pas uniquement “gratuit vs payant”).
Ce que je regarde pour trancher : est-ce que l’erreur arrive immédiatement (même sur un prompt minuscule), ou est-ce qu’elle arrive après un certain volume ? Est-ce que ça dépend d’un seul environnement ? Est-ce que le même modèle marche depuis un autre compte ? Et surtout : est-ce qu’il y a un incident public qui mentionne un comportement de rate limit / usage anormal ?
Runbook support : ce que tu dois collecter avant d’ouvrir un ticket (et qui te fera gagner du temps)
Le support, sans contexte, va te faire tourner en rond. Pas par malveillance, juste parce qu’ils voient passer des milliers de tickets identiques et qu’ils ont besoin de signaux précis.
Dans ton runbook, note noir sur blanc ce que tu collectes dès que ça casse : le plan/organisation concerné, le type de compte (ChatGPT vs API, selon ton cas), l’outil (CLI, app, extension, backend), le modèle exact, l’heure UTC, l’endpoint utilisé, et un exemple minimal reproductible. Ajoute aussi les headers ou request ids si tu les as. Et garde une capture du message d’erreur brut, pas juste « ça marche pas ».
Et détail important si tu as plusieurs chemins d’accès : précise si c’est le même comportement sur un autre modèle. Le support peut avancer beaucoup plus vite si tu prouves que « seul gpt-X casse » vs « tout casse ».
Mon avis : si ton business dépend d’un modèle, traite-le comme une dépendance critique, pas comme une librairie
On a tous tendance à intégrer un outil IA comme on intégrerait un SDK. Sauf que ce n’est pas un SDK. C’est un service vivant, avec des rollouts, des quotas, des incidents, des changements de support, et parfois des incohérences entre interfaces.
La bonne stratégie, ce n’est pas de “choisir le bon modèle une fois pour toutes”. C’est d’avoir un système qui encaisse le changement. Healthcheck quotidien, bascule sans déploiement, fallback mesuré, UX propre en mode dégradé. Tu n’empêcheras pas la plateforme de bouger, mais tu peux éviter de construire ton produit sur du sable.