CodeGym /Cours /ChatGPT Apps /Erreurs de déploiement typiques et stratégie de débogage

Erreurs de déploiement typiques et stratégie de débogage

ChatGPT Apps
Niveau 7 , Leçon 4
Disponible

1. Anatomie du déploiement : où cela peut-il casser

Il est utile de voir d’abord la chaîne complète. Le déploiement de ChatGPT App dans votre architecture peut se dérouler mentalement ainsi :

flowchart TD
  A[Votre ordinateur portable
git commit] --> B[Dépôt Git
GitHub/GitLab] B --> C[Build Vercel
npm run build] C --> D[Déploiement Vercel
Preview/Prod] D --> E[Endpoint HTTP
/mcp, /api/...] E --> F[ChatGPT / Dev Mode
appels d’outils, widgets]

Une erreur peut apparaître à n’importe quelle étape, mais les symptômes dans ChatGPT se ressemblent : "Error talking to app", "Network error" ou simplement du silence. Votre objectif est de ne pas tirer au hasard, mais d’identifier d’abord : est-ce tombé à l’étape de build, à l’exécution, ou ChatGPT pointe-t-il vers la mauvaise cible ?

Il est pratique de séparer les problèmes en trois grandes catégories :

  • Erreurs de build : Vercel n’a pas pu construire le projet. La production ne s’est pas mise à jour — c’est « bien » — mais vous voyez un build rouge.
  • Erreurs d’exécution (runtime) : le build est passé, mais les requêtes renvoient des 500/502, des timeouts ou un comportement étrange.
  • Config drift (dérive de configuration) : tout est OK en local, les logs Vercel sont OK, mais ChatGPT utilise une ancienne URL, travaille avec un manifeste ancien ou avec des variables d’environnement vides.

Nous allons parcourir ces trois couches et développer en parallèle une stratégie générale de débogage.

2. Erreurs de build : quand le projet ne se construit pas

C’est le premier type de problèmes de l’introduction — erreurs de build : le projet ne se construit pas du tout, car Vercel ne parvient pas à builder votre projet Next.js.

Node et Next.js : autre environnement, autres exigences

En local, vous pouvez (malheureusement) utiliser une version obsolète de Node, alors que Vercel essaiera de construire votre projet Next.js 16 avec une version de Node prise en charge (minimum 18.18.0). Si package.json indique explicitement une version incompatible, la build peut échouer en production alors que votre serveur de dev tournait.

Un moyen simple de se protéger est d’indiquer explicitement "engines" dans package.json :

{
  "engines": {
    "node": ">=18.18.0"
  }
}

Ainsi, en local comme en CI/sur Vercel, vous verrez à l’avance que Node est trop ancien.

« Chez moi ça marche ! » et dépendances oubliées

Classique : vous avez installé une bibliothèque via npm install some-lib, mais vous n’avez pas commité le package-lock.json mis à jour, ou bien certaines dépendances sont installées globalement. Sur Vercel, l’application est construite « from scratch » : il exécute npm install d’après le manifeste, mais votre chère some-lib n’y est pas — d’où une erreur de build.

Ce qui aide ici, c’est une discipline stricte :

  • toute nouvelle dépendance est ajoutée et immédiatement committée ;
  • avant de pousser sur main/production, vous lancez npm run build en local. Si la build locale échoue, ce sera pire sur Vercel.

Système de fichiers sensible à la casse

En local, beaucoup sont sur macOS ou Windows, où le système de fichiers ne distingue pas la casse des noms de fichiers par défaut. Sur Vercel, la build se fait dans un environnement Linux, où Widget.tsx et widget.tsx sont des fichiers différents.

Bogue typique :

// Import dans le code
import { AppWidget } from "@/components/Widget";

// Mais dans le dépôt le fichier est components/widget.tsx

Sur votre machine, tout fonctionne ; sur Vercel — erreur de module « Cannot find module '@/components/Widget' ». La solution est de remettre de l’ordre dans les noms et de respecter la casse.

Variables d’environnement au moment du build

Autre source de surprises — l’utilisation de process.env.* dans du code exécuté pendant la build (par exemple dans next.config.mjs ou des modules importés au build). Si vous avez chargé en local .env.local mais oublié de définir ces variables pour l’environnement de build sur Vercel, la build échouera, ou pire — passera avec undefined et « figera » des valeurs invalides dans le bundle.

Pour ChatGPT App, c’est particulièrement critique si, par exemple, vous formez un baseURL pour l’endpoint MCP ou des URLs d’API externes dès l’étape de build.

Bonne pratique : valider explicitement les variables d’environnement critiques avant même le démarrage de l’application (nous en parlerons dans une section dédiée), afin que la build échoue fort et de manière prévisible.

3. Erreurs d’exécution (runtime) : quand tout est construit, mais ne fonctionne pas

Passons maintenant à la deuxième couche de l’introduction — les erreurs d’exécution : la build est passée, mais à l’exécution, tout casse.

La build est passée, Vercel a affiché un déploiement vert, vous avez basculé ChatGPT App sur l’URL de prod — et vous obtenez dans le chat "Error talking to app". Les problèmes sont donc passés au niveau de l’exécution.

Variables d’environnement nulles ou vides

Le plus souvent, un incident de prod dans le monde de ChatGPT App commence par le mot undefined. En local, vous avez un soigné .env.local avec OPENAI_API_KEY, MCP_BASE_URL et autres, mais sur Vercel, vous avez oublié de définir ces variables ou vous avez confondu leurs noms.

Par exemple, vous lisez :

const apiKey = process.env.OPENAI_API_KEY;

mais sur Vercel, vous avez défini OPENAI_APIKEY ou OPENAI_API_KEY_PROD. En conséquence, dès le premier appel d’un outil MCP, votre route-handler tombe avec une erreur d’authentification.

Il est bien plus agréable que l’application tombe immédiatement et clairement. Un bon pattern est un module dédié dans votre projet Next.js qui valide les variables d’environnement à l’import :

// app/lib/env.ts
const required = ["OPENAI_API_KEY", "MCP_BASE_URL"] as const;

type RequiredKey = (typeof required)[number];

function getEnv(key: RequiredKey): string {
  const value = process.env[key];
  if (!value) {
    throw new Error(`Missing required env var: ${key}`);
  }
  return value;
}

export const env = {
  OPENAI_API_KEY: getEnv("OPENAI_API_KEY"),
  MCP_BASE_URL: getEnv("MCP_BASE_URL"),
};

Désormais, si vous avez oublié de configurer les variables sur Vercel, Next.js échouera dès le premier import de env, et les logs afficheront un message clair "Missing required env var: ...".

Important : sur Vercel, les changements de variables d’environnement ne sont pas pris en compte automatiquement. Après modification des valeurs, il faut faire un nouveau déploiement (redeploy), sinon le runtime continuera d’utiliser les anciennes valeurs.

Erreurs dans les route handlers et l’endpoint MCP

Dans le template officiel ChatGPT App, le serveur MCP est généralement implémenté comme app/mcp/route.ts. À l’intérieur, vous avez du code qui parse une requête JSON‑RPC, la route vers un outil et renvoie la réponse. Si un throw non géré se produit quelque part dans la chaîne — l’utilisateur recevra un 500 dans ChatGPT.

Il faut toujours envelopper le niveau supérieur du handler MCP dans un try/catch, journaliser l’erreur et renvoyer une réponse structurée :

// app/mcp/route.ts
import { NextRequest, NextResponse } from "next/server";

export const dynamic = "force-dynamic";
export const maxDuration = 30; // secondes

export async function POST(req: NextRequest) {
  try {
    const body = await req.json();
    // traitement de la requête MCP ici
    const result = await handleMcpRequest(body);
    return NextResponse.json(result);
  } catch (error) {
    console.error("MCP route error", error);
    return NextResponse.json(
      { error: "Internal MCP error" },
      { status: 500 }
    );
  }
}

Quelques points :

  • dynamic = "force-dynamic" aide à éviter une génération statique et une mise en cache inattendues pour les routes MCP dans Next.js 16.
  • maxDuration = 30 indique explicitement à Vercel que le route-handler peut s’exécuter jusqu’à 30 secondes, ce qui est important pour des requêtes LLM longues.

Timeouts et « Network error » dans ChatGPT

Vercel limite le temps d’exécution des fonctions serverless : sur les plans gratuits, c’est généralement environ 10 secondes, sur les payants cela peut être plus (jusqu’à plusieurs minutes). Si votre outil MCP effectue une requête longue vers une base ou une API externe, il peut ne pas répondre à temps, et ChatGPT recevra "Network error" ou un flux interrompu.

Si vous utilisez le streaming (SSE) pour des résultats partiels, il est particulièrement important d’envoyer les premiers octets de la réponse avant l’expiration du timeout. La transmission elle-même peut alors durer plus longtemps, mais la plateforme ne considérera pas la fonction comme « bloquée ».

Astuce : mesurez la durée d’appel des outils et journalisez-la avec le nom de l’outil. Ainsi, dans les logs, on verra par exemple que search_flights prend régulièrement 12 secondes et dépasse légèrement la limite.

export async function safeToolCall<TInput, TOutput>(
  name: string,
  handler: (input: TInput) => Promise<TOutput>,
  input: TInput
): Promise<TOutput> {
  const started = Date.now();
  try {
    const result = await handler(input);
    console.log("[tool] ok", name, { ms: Date.now() - started });
    return result;
  } catch (error) {
    console.error("[tool] fail", name, {
      ms: Date.now() - started,
      error,
    });
    throw error;
  }
}

Ensuite, au lieu d’appeler handler(args), vous appelez safeToolCall("search_flights", handler, args).

Réseau et services externes

Parfois, tout vient d’un simple https:// au lieu de http:// ou d’un baseURL obsolète. Surtout si vous avez d’abord testé en local avec une URL, mais qu’en production vous avez un autre domaine ou un autre port.

Il est utile d’extraire les URLs de base dans une configuration (dépendante de l’environnement) et de ne pas les coder en dur dans l’outil. Ainsi, lors d’un changement d’environnement, vous ne modifiez qu’une variable d’environnement, au lieu de vous souvenir des cinq endroits dans le code où traînait http://localhost:3001.

4. Configuration et dérive des environnements

Enfin, le troisième type de notre schéma — la dérive de configuration entre environnements.

Même si la build est passée et que le runtime a l’air sain dans les logs, ChatGPT peut se comporter « comme si ce n’était pas la bonne version de l’application ». C’est précisément le cas où le problème n’est pas tant dans le code que dans la configuration et la cohérence des environnements.

Dev Mode vs production

En Dev Mode, ChatGPT regarde l’URL du connecteur que vous avez indiquée manuellement : généralement une URL de tunnel (https://myapp-dev.ngrok-free.app/mcp ou similaire) ou une URL de staging sur Vercel. En production (via le Store ou les paramètres d’organisation), l’App doit pointer vers un endpoint de production stable, par exemple https://myapp.vercel.app/mcp.

Erreur courante : vous avez déployé sur Vercel, mais dans les paramètres de ChatGPT App, l’ancienne URL de tunnel est encore renseignée. Le serveur local est éteint, le tunnel est mort depuis longtemps, et ChatGPT frappe consciencieusement cette URL et obtient un 502. Dans l’interface, cela ressemble à "Error talking to app", et l’étudiant commence à réparer le code MCP qui ne s’exécute pas du tout.

La solution est la discipline : après tout changement d’environnement (tunnel → staging, staging → prod), vérifiez quelle URL est indiquée dans le Dev Mode et dans la configuration de production de l’App.

Ancien manifeste et cache de ChatGPT

ChatGPT mettra en cache les informations sur votre App : liste des outils, leurs descriptions, métadonnées. Ainsi, la situation « j’ai changé le schéma d’un outil, mais le modèle pense encore que l’argument s’appelle comme avant » — est bien réelle.

En cas de modifications importantes des outils, il est utile de :

  • vous assurer que vous avez bien déployé la nouvelle version (regarder le hash du commit dans les logs, l’afficher dans un log de démarrage) ;
  • recréer ou reconnecter l’App en Dev Mode pour forcer la plateforme à relire le manifeste ;
  • pendant le débogage, travailler via MCP Inspector, où vous voyez exactement la liste et les schémas à jour des outils.

Configuration des variables d’environnement : dev/staging/prod

Nous avons déjà parlé de la manière dont les variables d’environnement peuvent faire échouer la build et le runtime. Ici — un regard d’ensemble sur dev/staging/prod et la cohérence des valeurs entre eux.

Douleur fréquente : votre .env.local est parfait, mais les environnements Vercel — c’est le bazar. Au final :

  • en local, vous avez une clé d’API et une URL de service externe ;
  • sur staging — des valeurs complètement différentes ;
  • en prod — la moitié des variables ne sont pas définies.

Un simple fichier texte docs/env.md dans le dépôt aide énormément, où vous listez : quelles variables sont nécessaires, dans quels environnements elles sont obligatoires, et des valeurs d’exemple. Cela peut sembler bureaucratique, mais lors d’un incident, une telle liste fait gagner des heures.

5. À quoi ressemblent les erreurs côté ChatGPT

Voyons maintenant la situation avec les yeux de l’utilisateur de ChatGPT. Il ne voit que l’interface et ne sait rien de Vercel, Node ni MCP. Et vous, malheureusement, ne savez pas encore ce qui a cassé.

Symptômes typiques dans ChatGPT :

  • message "Error talking to [App Name]" juste après la tentative d’utilisation ;
  • spinner infini sans erreur visible ;
  • texte rouge "I encountered an error while running the tool" ;
  • le widget n’apparaît pas ou apparaît vide.

Chacun de ces symptômes correspond généralement à un niveau de panne précis :

  • si l’App est totalement indisponible (mauvaise URL, tunnel tombé, erreur SSL), ChatGPT ne peut pas joindre votre endpoint MCP — vérifiez l’accessibilité du domaine dans un navigateur et les logs Vercel avec des codes 4xx/5xx ;
  • si MCP répond avec un JSON‑RPC valide contenant un champ error, ChatGPT indique honnêtement que l’outil a renvoyé une erreur — c’est alors une question de logique métier ou de validation des arguments ;
  • si MCP répond correctement, mais que le HTML du widget est cassé ou qu’il y a une erreur JS, la console du widget (DevTools → iframe du widget) montrera ce qui a planté.

D’où une bonne habitude : dès que vous voyez un comportement étrange dans le chat, prenez immédiatement un timestamp (à la minute près) et allez dans les logs Vercel chercher les requêtes à ce moment-là.

6. Stratégie de débogage : ne pas paniquer, mais agir

Assemblons maintenant un petit « playbook » à partir de tout ce qui a été dit — un scénario d’actions quand quelque chose tourne mal. L’objectif est de remplacer la course en rond par un algorithme serein.

Étape 1 : déterminer le type de problème

Si la build sur Vercel est rouge — réjouissez‑vous : l’erreur a été interceptée avant la production. Ouvrez les logs de build, regardez la première erreur réelle (et non 200 lignes d’avertissements) et reproduisez en local avec npm run build.

Si la build est verte et que ChatGPT se plaint — c’est du runtime ou de la config. Vérifiez :

  • si l’URL de prod de votre App est accessible depuis un navigateur (https://myapp.vercel.app/mcp renvoie‑t‑elle quelque chose) ;
  • si l’endpoint MCP renvoie un 200/500 ou ne résout pas du tout ;
  • si l’URL dans les paramètres de l’App correspond bien à celle que vous venez de vérifier.

Étape 2 : lire les logs, pas dans les pensées

Prochaine étape — les logs Vercel : logs serveur pour le déploiement et l’environnement concernés (Preview/Production).

Recherchez :

  • des erreurs Error: Missing required env var ... — le problème vient de la configuration ;
  • une stack trace depuis le handler MCP — la logique métier ou le parsing des données d’entrée plante ;
  • des messages de timeout ou de dépassement de durée de la fonction.

En parallèle, n’oubliez pas MCP Inspector. Si vous vous connectez au même endpoint MCP via l’inspecteur et appelez les outils manuellement, vous verrez rapidement si le problème vient du MCP lui‑même ou du couple ChatGPT ↔ MCP.

Étape 3 : rollback rapide ou hotfix ?

Si vous voyez que le déploiement de prod est clairement cassé (par exemple, la route MCP lève la même erreur à chaque requête), et que le déploiement précédent était sain, la bonne décision est de revenir en arrière. Vercel permet de repasser rapidement au déploiement réussi précédent sans rebuild — c’est en substance un changement de version active.

C’est mieux que d’essayer de réparer la production « à chaud », surtout si vous ne comprenez pas encore la cause de l’incident.

Une fois la situation stabilisée, analysez calmement la cause, écrivez des tests, corrigez dans le code et ne publiez la version suivante qu’ensuite.

Étape 4 : capitaliser par la documentation

Tout incident sérieux est l’occasion de mettre à jour le README interne :

  • ajouter une variable d’environnement obligatoire sans laquelle tout tombe ;
  • noter quel cas précis a conduit à l’erreur (par exemple « import avec une casse incorrecte des noms de fichiers ») ;
  • décrire l’algorithme d’actions court qui a permis de tout réparer rapidement.

Cela peut sembler ennuyeux, mais dans quelques mois vous vous en remercierez.

7. Quelques pratiques concrètes dans le code

Prenons maintenant quelques étapes de notre playbook et ancrons‑les par de petites pratiques de code dans notre application d’apprentissage (ChatGPT App).

Module de configuration unifié

Nous avons déjà écrit un simple validateur de variables d’environnement. On peut le compléter pour distinguer les environnements :

// app/lib/config.ts
type NodeEnv = "development" | "test" | "production";

const nodeEnv = (process.env.NODE_ENV || "development") as NodeEnv;

const requiredBase = ["OPENAI_API_KEY"] as const;
const requiredProd = ["MCP_BASE_URL"] as const;

function ensure(keys: readonly string[]) {
  for (const key of keys) {
    if (!process.env[key]) {
      throw new Error(`Missing env var ${key} for NODE_ENV=${nodeEnv}`);
    }
  }
}

ensure(requiredBase);
if (nodeEnv === "production") {
  ensure(requiredProd);
}

export const config = {
  nodeEnv,
  openaiApiKey: process.env.OPENAI_API_KEY!,
  mcpBaseUrl: process.env.MCP_BASE_URL ?? "http://localhost:3000/mcp",
};

Un tel module vous signalera immédiatement si la prod est lancée sans la variable nécessaire.

Journalisation des requêtes MCP entrantes

Un habillage simple mais très utile pour le handler MCP :

// app/lib/mcp-logger.ts
export function logMcpRequest(body: unknown) {
  console.log("[mcp] request", {
    time: new Date().toISOString(),
    // ne journalisons pas les données sensibles
    keys: typeof body === "object" && body !== null
      ? Object.keys(body as Record<string, unknown>)
      : typeof body,
  });
}

Et nous l’utilisons dans app/mcp/route.ts :

import { logMcpRequest } from "@/app/lib/mcp-logger";

export async function POST(req: NextRequest) {
  try {
    const body = await req.json();
    logMcpRequest(body);
    const result = await handleMcpRequest(body);
    return NextResponse.json(result);
  } catch (error) {
    console.error("MCP route error", error);
    return NextResponse.json({ error: "Internal error" }, { status: 500 });
  }
}

Dans les logs, vous verrez ce qui arrive depuis ChatGPT : au moins par les clés ("jsonrpc", "method", "params"), et il sera plus facile de comprendre quel appel exact échoue.

Vérification simple de la disponibilité de l’endpoint MCP

Il est parfois utile d’avoir un petit route-handler de type « healthcheck » pour le serveur MCP, que ChatGPT n’appelle pas directement, mais que vous pouvez ouvrir rapidement dans un navigateur pour vérifier si le serveur est vivant et s’il voit ses variables d’environnement :

// app/api/health/route.ts
import { NextResponse } from "next/server";
import { config } from "@/app/lib/config";

export async function GET() {
  return NextResponse.json({
    status: "ok",
    env: config.nodeEnv,
    hasOpenAiKey: !!config.openaiApiKey,
  });
}

Si https://myapp.vercel.app/api/health répond status: "ok", alors au moins le pipeline de base jusqu’à votre code Node est opérationnel.

8. Erreurs courantes lors du déploiement et du débogage

Erreur n° 1 : déploiement sans npm run build en local.
Quand un développeur ne lance jamais la build en local, il découvre la version incompatible de Node, un problème de chemins ou une erreur TS uniquement sur Vercel. Cela allonge le cycle « cassé → réparé », car chaque essai est un nouveau déploiement. L’habitude d’exécuter npm run build avant de pousser sur main fait gagner beaucoup de temps (voir aussi la section 2 et l’étape 6.1 sur le npm run build local).

Erreur n° 2 : les secrets ne sont que dans .env.local.
Le projet fonctionne parfaitement sur la machine de l’auteur, mais tombe en prod parce que process.env.OPENAI_API_KEY === undefined. La raison est banale : les variables d’environnement ont été oubliées dans les paramètres Vercel (et parfois même nommées différemment). On oublie souvent la séparation Development/Preview/Production et on s’étonne que staging et prod se comportent différemment (détails — sections 3.1, 4.3 et 7.1).

Erreur n° 3 : utiliser NEXT_PUBLIC_* pour des secrets.
Dans Next.js, toutes les variables préfixées par NEXT_PUBLIC_ se retrouvent dans le bundle navigateur. Si par inadvertance vous avez nommé une clé d’API NEXT_PUBLIC_OPENAI_API_KEY, elle ira chez l’utilisateur dans le navigateur et pourra être récupérée via les devtools. À ne jamais faire. Seules des valeurs sûres doivent être publiques (par exemple, des identifiants de feature flags, mais pas des tokens).

Erreur n° 4 : ignorer les logs Vercel et tenter de « réparer via ChatGPT ».
Parfois, un développeur voit dans le chat "Error talking to app" et passe des heures à changer des prompts, des descriptions d’outils, à modifier quelque chose dans le Dev Mode, sans jamais ouvrir les logs serverless. Alors qu’ils affichent une erreur parfaitement compréhensible : "Missing env var", "Cannot find module" ou la stack trace d’un outil concret. Un bon ingénieur regarde d’abord les logs, puis discute avec le modèle.

Erreur n° 5 : confusion entre Dev Mode et App de production.
Après un premier déploiement réussi sur Vercel, on oublie facilement que le Dev Mode peut toujours pointer vers un ancien tunnel ou un preview‑URL. Au final, vous pensez tester la version de production, alors qu’en réalité vous parlez à une branche locale qu’il est grand temps de supprimer. Ou l’inverse : vous pensez tester des brouillons, mais ChatGPT frappe l’endpoint de production. Vérifiez régulièrement quelle URL est indiquée dans les paramètres de l’App et dans le Dev Mode (voir aussi la section 4.1 sur le Dev Mode et la production).

Erreur n° 6 : attendre qu’un changement de variable d’environnement sur Vercel prenne effet « à la volée ».
Certains étudiants modifient des variables dans le panneau Vercel et vont aussitôt dans ChatGPT vérifier le résultat. Mais le runtime utilise toujours les anciennes valeurs, car il n’y a pas eu de redeploy. Tout changement de variables d’environnement requiert un nouveau déploiement, sinon la fonction ne verra pas la mise à jour (détails — section 3.1).

Erreur n° 7 : absence d’une stratégie simple de rollback.
En cas d’incident, la tentation est grande de « pousser vite un correctif » directement sur main. Mais cela ajoute un autre déploiement potentiellement cassé, pendant que les utilisateurs subissent. Il est plus serein d’avoir l’habitude suivante : en cas d’erreur sérieuse, revenir immédiatement au dernier déploiement réussi, corriger le problème dans une branche séparée, puis seulement publier une nouvelle version. Vercel offre une interface pratique pour cela, ce serait dommage de ne pas en profiter.

1
Étude/Quiz
Débogage et déploiement, niveau 7, leçon 4
Indisponible
Débogage et déploiement
Environnements, débogage et déploiement (Vercel + tunnel)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION