Aller au contenu
Neaptidestudio
blog

Sitemap Next.js en 404 : quatre contrôles en dev et en production

Neaptide · 13 octobre 2026 · 7 min de lecture

Test reproductible sous Next.js 15.5.22 : distinguer une route absente, une source en erreur et une URL en 404 dans un XML valide. Correctifs et données brutes.

Dans cet article
Trois pannes de sitemap observées : route en 404, source provoquant une erreur 500 et page en 404 listée dans un sitemap en 200.

Avant de modifier la configuration de votre sitemap Next.js, identifiez précisément quelle URL échoue. Le point d’accès du sitemap, la source de données qui le génère et une fiche produit référencée à l’intérieur du XML peuvent tomber en erreur indépendamment les uns des autres. Une simple capture d’écran d’une page 404 ne permet pas de savoir quelle couche corriger.

Le 12 octobre 2026, Neaptide a testé quatre cas contrôlés. Une mauvaise adresse de sitemap a renvoyé un code 404 ; une source indisponible a provoqué une erreur 500 parce que notre gestionnaire d’appel levait explicitement une exception ; enfin, un sitemap incluant un produit retiré du catalogue a bien répondu en 200 alors que la fiche de ce produit renvoyait 404. Chaque correctif a fonctionné à l’identique sous next dev et sur un build de production local, sans aucun écart entre les deux modes.

Ce que nous avons testé avant d’écrire ce guide

Le banc d’essai repose sur Next.js 15.5.22, React et React DOM 19.2.6, Node v25.2.1 et deux produits fictifs. Nous avons figé le protocole, le code source, le script de collecte et le fichier de verrouillage des dépendances avant les mesures, installé les paquets dans un répertoire isolé, puis exécuté en parallèle next dev et next build suivi de next start. Un flux HTTP local fournit les fiches produits. Ce build de production local ne teste pas l’infrastructure de Vercel.

Les quatre cas se déclinent en sept variantes : un témoin sain et trois paires avant/après. Deux environnements croisés sur deux passages produisent 28 réponses de sitemap, auxquelles s’ajoutent 36 requêtes vers les URL référencées dans le XML et deux contrôles du flux source. Il s’agit de 66 observations HTTP répétées, et non de 66 URL distinctes. Nous avons archivé les corps de réponse, les en-têtes et les empreintes de hachage. Le contrôle XML vérifie le bon décodage syntaxique et l’espace de noms urlset, sans validation XSD exhaustive.

Pourquoi le seul code HTTP du sitemap a masqué une erreur

Codes HTTP mesurés sur le sitemap et sur les pages listées pour le témoin et les trois paires avant/après ; résultats identiques en dev et en production.
Banc d’essai Neaptide, 12 octobre 2026. Chaque ligne regroupe quatre observations concordantes : deux environnements × deux passages. Un tiret signifie qu’aucun bloc urlset n’a pu être décodé, et non zéro URL. L’ordre des codes suit celui du XML.
Banc d’essai Neaptide, 12 octobre 2026. Chaque ligne regroupe quatre observations concordantes : deux environnements × deux passages. Un tiret signifie qu’aucun bloc urlset n’a pu être décodé, et non zéro URL. L’ordre des codes suit celui du XML.
CasÉtatHTTP sitemapURL dans le XMLHTTP des pages listées
Témoin statiqueTémoin2002200 / 200
Source dynamiqueAvant500——
Source dynamiqueAprès2002200 / 200
Route demandéeAvant404——
Route demandéeAprès2002200 / 200
Produit retiréAvant2002200 / 404
Produit retiréAprès2001200

Pourquoi une source en 404 a provoqué une erreur 500 sur le sitemap

Le sitemap dynamique interroge un flux JSON contrôlé. Avant correction, son chemin pointait vers /missing-catalog.json, qui renvoyait un code 404. Le gestionnaire ci-dessous teste response.ok et lève explicitement une exception : c’est cette erreur non interceptée qui a généré une réponse 500 sur /dynamic-bad/sitemap.xml. Ce résultat découle directement de notre gestion d’erreurs ; Next.js ne transforme pas automatiquement toute erreur 404 en amont en erreur 500.

// lib/catalog.js
export async function fromFeed(path) {
  const response=await fetch(`http://127.0.0.1:8800${path}`,{cache:'no-store'});
  if(!response.ok) throw new Error(`Controlled catalog source returned HTTP ${response.status}`);
  const rows=await response.json();return entries(rows.map(row=>row.slug));
}

Corriger le chemin du flux en /catalog.json a suffi : /dynamic-ok/sitemap.xml a renvoyé un code 200 avec deux fiches produits accessibles. Les deux variantes utilisaient déjà force-dynamic et cache: 'no-store' ; passer en rendu dynamique n’était donc pas le correctif testé ici. Sur votre propre application, relevez le code HTTP renvoyé en amont et consultez les journaux serveur avant de modifier la stratégie de cache.

// app/dynamic-ok/sitemap.js
import {fromFeed} from '../../lib/catalog';
export const dynamic='force-dynamic';
export default async function sitemap(){return fromFeed('/catalog.json');}

Vérifier l’URL générée selon l’emplacement du fichier

Notre fichier imbriqué app/catalog/sitemap.js exposait la route /catalog/sitemap.xml. Appeler /sitemaps/catalog.xml renvoyait donc un code 404, tandis qu’interroger la route réelle renvoyait immédiatement 200 sans toucher au code du sitemap. Le témoin racine app/sitemap.js répondait lui aussi en 200. Ces chemins découlent directement de la convention de fichiers documentée par Next.js ; le découpage en plusieurs fichiers via generateSitemaps sortait du périmètre de ce test.

app/sitemap.js          → /sitemap.xml
app/catalog/sitemap.js  → /catalog/sitemap.xml

Un sitemap en 200 peut malgré tout référencer une page en 404

La variante stale-before exportait l’intégralité des entrées éditoriales, y compris /products/retired. Le XML était valide et le sitemap répondait en 200, mais l’URL du produit retiré renvoyait 404. Filtrer les entrées sur le booléen published avant de générer les URL n’a conservé qu’une seule référence, /products/widget-a, bien servie en 200. Nous avons simplement exclu l’entrée dépubliée, sans mettre en place de redirection ni la remplacer par un autre produit.

// app/stale-after/sitemap.js
import {editorialRecords,entries} from '../../lib/catalog';
export default function sitemap(){return entries(editorialRecords.filter(row=>row.published).map(row=>row.slug));}

Un simple indicateur published ne constitue pas à lui seul une règle complète d’indexabilité. Sur un catalogue réel, vérifiez également que les URL retenues correspondent bien aux URL canoniques cibles et qu’elles sont autorisées à l’indexation. Les pages de notre banc d’essai embarquent volontairement noindex/nofollow : cette expérience contrôle la disponibilité HTTP des routes, et non leur éligibilité dans les moteurs.

Remonter la chaîne à partir de l’URL en échec

Partez toujours d’une requête GET sur l’URL exacte du sitemap déclaré, en enregistrant le code HTTP et le corps de la réponse avant toute redirection. L’arbre de décision ci-dessous constitue une checklist opérationnelle : les branches portant sur un XML mal formé ou sur un incident propre à l’hébergeur relèvent de bonnes pratiques complémentaires, et non de cas mesurés lors du test.

Arbre de diagnostic : un code 404 sur le sitemap oriente vers le contrôle de la route, un code 5xx vers la source et les journaux serveur, et un code 200 vers l’analyse XML suivie du test des URL loc.
Guide de diagnostic tiré des cas mesurés. Une réponse 200 exige encore de contrôler le XML et chacune de ses URL ; les pannes propres à l’hébergement n’ont pas été testées.
  1. Le sitemap renvoie 404 : comparez le chemin appelé avec la route réelle et l’emplacement du fichier dans app/. Dans le cas S3, appeler la bonne adresse a suffi à lever l’erreur.
  2. Le sitemap renvoie 5xx : inspectez l’erreur serveur de la route ainsi que la réponse de sa source de données. Dans le cas S2, la source introuvable provoquait une exception ; corriger son chemin a rétabli le service.
  3. Le sitemap renvoie 200 : décodez le corps de réponse et vérifiez l’espace de noms racine. Si vous recevez du HTML ou un XML mal formé, inspectez la route qui génère cette sortie (cas non injecté dans notre test).
  4. Le XML est valide : interrogez les URL contenues dans <loc> et relevez leurs codes HTTP. Dans le cas S4, cette étape a mis au jour le produit retiré qu’un contrôle limité au seul sitemap laissait passer.
  5. L’anomalie ne survient qu’en ligne : comparez le même commit, le chemin appelé, les variables d’environnement et l’accessibilité de la source avec un lancement local via next build puis next start, avant d’examiner le routage et les journaux de la plateforme. Notre expérience locale n’a isolé aucun défaut lié à l’hébergement.

Google recommande d’inclure uniquement des URL absolues correspondant aux pages canoniques que vous souhaitez voir apparaître dans les résultats. L’envoi d’un sitemap reste un signal indicatif et ne garantit pas l’exploration. Après la mise en ligne, vérifiez le rapport Sitemaps de la Google Search Console pour repérer d’éventuelles erreurs de lecture : une réponse HTTP locale valide ne préjuge pas du traitement côté Google.

Rejouer les contrôles avec le même banc d’essai

Téléchargez l’archive de reproduction et suivez les instructions de README.txt. Démarrez le flux local, installez les dépendances figées, puis lancez les serveurs de développement et de production sur les ports 8801 et 8802. Le script de collecte enregistre toute la matrice sans suivre les redirections ni interroger de domaines externes. Nous avons vérifié la conformité de l’archive avec le code figé, puis relancé son collecteur sur les serveurs initiaux : les 28 empreintes de sitemaps concordaient parfaitement (ce contrôle ne constituait toutefois pas une réinstallation complète à froid des serveurs).

Méthode, données brutes et exemple exécutable

Ces pannes injectées volontairement éclairent le diagnostic mais n’indiquent rien sur la fréquence réelle de chaque cause en production. Nous n’avons testé ni CMS réel, ni invalidation de cache, ni middleware, ni règles de réécriture (rewrites), ni CDN, ni déploiement sur Vercel, et nous n’avons mesuré ni l’indexation, ni les positions, ni les citations par les moteurs IA. Un ticket historique Next.js RC/Windows/Prisma a aidé à cadrer la question ; notre banc d’essai ne cherche ni à reproduire ni à résoudre cet environnement particulier.

faq

L’essentiel en bref

Faut-il ajouter force-dynamic pour corriger un sitemap en 404 ?

Identifiez d’abord quelle URL échoue et quel code elle renvoie. Dans notre expérience, les deux variantes dynamiques utilisaient déjà force-dynamic : la correction portait sur le chemin du flux source. Quant à l’erreur 404 sur l’adresse du sitemap, il suffisait d’interroger la route réellement générée. L’invalidation de cache n’a pas été testée dans cette étude.

Un sitemap qui répond en 200 garantit-il que toutes les pages listées fonctionnent ?

Non. Notre variante obsolète renvoyait un code 200 avec un XML valide, alors qu’une fiche produit listée répondait en 404. Contrôlez séparément les URL référencées : sur un site en production, même une page en 200 exige un contrôle de sa balise canonical et de son indexabilité.