diff --git a/.changeset/yellow-icons-attack.md b/.changeset/yellow-icons-attack.md new file mode 100644 index 000000000000..93be1fcd91fb --- /dev/null +++ b/.changeset/yellow-icons-attack.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Raise error when multiple content collection entries have the same slug diff --git a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts index bd516b199c82..33aae964d890 100644 --- a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts +++ b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts @@ -166,6 +166,16 @@ export async function getStringifiedLookupMap({ fileUrl: pathToFileURL(filePath), contentEntryType, }); + if (lookupMap[collection]?.entries?.[slug]) { + throw new AstroError({ + ...AstroErrorData.DuplicateContentEntrySlugError, + message: AstroErrorData.DuplicateContentEntrySlugError.message(collection, slug), + hint: + slug !== generatedSlug + ? `Check the \`slug\` frontmatter property in **${id}**.` + : undefined, + }); + } lookupMap[collection] = { type: 'content', entries: { diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts index 0425eb22e060..5fa2b4b5c7f1 100644 --- a/packages/astro/src/core/errors/errors-data.ts +++ b/packages/astro/src/core/errors/errors-data.ts @@ -1112,6 +1112,18 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati }, hint: 'Ensure your data entry is an object with valid JSON (for `.json` entries) or YAML (for `.yaml` entries).', }, + /** + * @docs + * @description + * Content collection entries must have unique slugs. Duplicates are often caused by the `slug` frontmatter property. + */ + DuplicateContentEntrySlugError: { + title: 'Duplicate content entry slug.', + code: 9008, + message: (collection: string, slug: string) => { + return `**${collection}** contains multiple entries with the same slug: \`${slug}\`. Slugs must be unique.`; + }, + }, // Generic catch-all - Only use this in extreme cases, like if there was a cosmic ray bit flip UnknownError: {