{"record":{"id":"f3efe33926c4926a","repo":"withastro/astro","slug":"rss-you-can-only-glob-entries-within-src-pages","errorCode":null,"errorMessage":"[RSS] You can only glob entries within 'src/pages/' when passing import.meta.glob() directly. Consider mapping the result to an array of RSSFeedItems. See the RSS docs for usage examples: https://docs.astro.build/en/recipes/rss/","messagePattern":"\\[RSS\\] You can only glob entries within 'src/pages/' when passing import\\.meta\\.glob\\(\\) directly\\. Consider mapping the result to an array of RSSFeedItems\\. See the RSS docs for usage examples: https://docs\\.astro\\.build/en/recipes/rss/","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro-rss/src/index.ts","lineNumber":138,"sourceCode":"\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t`The \\`items\\` property requires at least the \\`title\\` or \\`description\\` key. They must be properly typed, as well as \\`pubDate\\` and \\`link\\` keys if provided.`,\n\t\t\t\t\t\t`Check your collection's schema, and visit https://docs.astro.build/en/recipes/rss/#generating-items for more info.`,\n\t\t\t\t\t].join('\\n');\n\t\t\t\t}\n\n\t\t\t\treturn message;\n\t\t\t}),\n\t\t].join('\\n'),\n\t);\n\tthrow formattedError;\n}\n\nexport function pagesGlobToRssItems(items: GlobResult): Promise<ValidatedRSSFeedItem[]> {\n\treturn Promise.all(\n\t\tObject.entries(items).map(async ([filePath, getInfo]) => {\n\t\t\tconst { url, frontmatter } = await getInfo();\n\t\t\tif (url === undefined || url === null) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[RSS] You can only glob entries within 'src/pages/' when passing import.meta.glob() directly. Consider mapping the result to an array of RSSFeedItems. See the RSS docs for usage examples: https://docs.astro.build/en/recipes/rss/`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst parsedResult = rssSchema\n\t\t\t\t.refine((val) => val.title || val.description, {\n\t\t\t\t\tmessage: 'At least title or description must be provided.',\n\t\t\t\t\tpath: ['title', 'description'],\n\t\t\t\t})\n\t\t\t\t.safeParse({ ...frontmatter, link: url });\n\n\t\t\tif (parsedResult.success) {\n\t\t\t\treturn parsedResult.data;\n\t\t\t}\n\t\t\tconst formattedError = new Error(\n\t\t\t\t[\n\t\t\t\t\t`[RSS] ${filePath} has invalid or missing frontmatter.\\nFix the following properties:`,\n\t\t\t\t\t...parsedResult.error.issues.map((zodError) => zodError.message),\n\t\t\t\t].join('\\n'),","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro-rss/src/index.ts#L120-L156","documentation":"The @astrojs/rss helper pagesGlobToRssItems() converts a raw import.meta.glob() result into RSS items by reading each module's `url` export. Vite only injects a route `url` into modules that live under src/pages/, because only those become routable pages. When a globbed entry's `url` is undefined or null, the helper cannot build a feed link and aborts with this error.","triggerScenarios":"Passing import.meta.glob() of files outside src/pages/ directly to the RSS `items` option — e.g. globbing src/content/blog/*.md or a root-level posts/ directory from src/pages/rss.xml.js. Also globbing non-route files (data .md/.json that never become pages) so the loaded module has no `url` export.","commonSituations":"Migrating a blog where content lives in src/content or a top-level posts folder instead of src/pages; following older RSS examples that assumed pages-directory content; switching from explicit item arrays to glob shorthand in an Astro + @astrojs/rss setup.","solutions":["Map the glob result to an array of RSSFeedItem objects yourself instead of passing it directly: pull title/description/pubDate from each module's frontmatter and set `link` to the real page URL","If you want automatic URLs, move the globbed files under src/pages/ so each entry is a routable page","Glob the content for metadata only and construct links from your known route pattern (e.g. `/blog/${slug}/`)"],"exampleFix":"// before (in src/pages/rss.xml.js)\nimport rss from '@astrojs/rss';\nexport const get = () => rss({\n  items: import.meta.glob('../content/blog/*.md'), // outside src/pages/ -> throws\n});\n\n// after\nimport rss from '@astrojs/rss';\nconst posts = Object.entries(import.meta.glob('../content/blog/*.md'));\nexport const get = async () => rss({\n  title: 'My Blog',\n  items: await Promise.all(\n    posts.map(async ([file, getInfo]) => {\n      const { frontmatter } = await getInfo();\n      const slug = file.split('/').pop().replace('.md', '');\n      return {\n        title: frontmatter.title,\n        description: frontmatter.description,\n        pubDate: frontmatter.pubDate,\n        link: `/blog/${slug}/`,\n      };\n    })\n  ),\n});","handlingStrategy":"validation","validationCode":"// before building the feed, confirm every glob entry yields a route URL\nconst entries = Object.entries(import.meta.glob('./posts/*.md'));\nconst withUrls = await Promise.all(\n  entries.map(async ([file, getInfo]) => {\n    const mod = await getInfo();\n    return { file, mod, hasUrl: mod.url != null };\n  })\n);\nif (withUrls.some((e) => !e.hasUrl)) {\n  throw new Error(`Glob outside src/pages/ detected for: ${withUrls.filter((e) => !e.hasUrl).map((e) => e.file).join(', ')}`);\n}","typeGuard":"function isRssGlobCandidate(items: Record<string, () => Promise<{ url?: unknown }>>): boolean {\n  return Object.keys(items).every((p) => p.startsWith('/src/pages/'));\n}","tryCatchPattern":"try {\n  const feedItems = await pagesGlobToRssItems(import.meta.glob('./*.md'));\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"glob entries within 'src/pages/'\")) {\n    // fall back to manual mapping from frontmatter + known route pattern\n  } else throw e;\n}","preventionTips":["Only pass import.meta.glob() directly to RSS when the glob target is inside src/pages/","Keep content used for feeds either in src/pages/ or behind a content collection, and map to RSSFeedItem[] explicitly","Loudly fail in CI by building the RSS route (astro build) so glob mistakes surface before deploy"],"tags":["rss","import-meta-glob","vite","content-collections","astro-rss"],"backgroundTag":"import-meta-glob-outside-root","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}