{"record":{"id":"de9c71f15069bbd4","repo":"withastro/astro","slug":"colors-bold-normalizepath-path-relative-fileurlt","errorCode":null,"errorMessage":"${colors.bold(normalizePath(path.relative(fileURLToPath(contentPaths.contentDir), fileURLToPath(event.entry))))} must live in a ${colors.bold('content/...')} collection subdirectory.","messagePattern":"(.+?) must live in a (.+?) collection subdirectory\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/astro/src/content/types-generator.ts","lineNumber":156,"sourceCode":"\t\t}\n\t\tif (fileType === 'config') {\n\t\t\tawait reloadContentConfigObserver({\n\t\t\t\tfs,\n\t\t\t\tsettings,\n\t\t\t\tenvironment: viteServer.environments[\n\t\t\t\t\tASTRO_VITE_ENVIRONMENT_NAMES.astro\n\t\t\t\t] as RunnableDevEnvironment,\n\t\t\t\tlogger,\n\t\t\t});\n\t\t\treturn { shouldGenerateTypes: true };\n\t\t}\n\n\t\tconst { entry } = event;\n\t\tconst { contentDir } = contentPaths;\n\n\t\tconst collection = getEntryCollectionName({ entry, contentDir });\n\t\tif (collection === undefined) {\n\t\t\tlogger.warn(\n\t\t\t\t'content',\n\t\t\t\t`${colors.bold(\n\t\t\t\t\tnormalizePath(\n\t\t\t\t\t\tpath.relative(fileURLToPath(contentPaths.contentDir), fileURLToPath(event.entry)),\n\t\t\t\t\t),\n\t\t\t\t)} must live in a ${colors.bold('content/...')} collection subdirectory.`,\n\t\t\t);\n\t\t\treturn { shouldGenerateTypes: false };\n\t\t}\n\n\t\tif (fileType === 'data') {\n\t\t\tconst id = getDataEntryId({ entry, contentDir, collection });\n\t\t\tconst collectionKey = JSON.stringify(collection);\n\t\t\tconst entryKey = JSON.stringify(id);\n\n\t\t\tswitch (event.name) {\n\t\t\t\tcase 'add':\n\t\t\t\t\tif (!(collectionKey in collectionEntryMap)) {","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/withastro/astro/blob/e294953aa8aadd98d5be92e60a03037b05dbdfd4/packages/astro/src/content/types-generator.ts#L138-L174","documentation":"During content type generation (astro sync or dev-server events), a file under src/content could not be assigned a collection because it sits directly in the content root instead of a collection subdirectory (src/content/<collection>/...). Astro warns with the relative path and returns shouldGenerateTypes: false, so no types are generated for that file.","triggerScenarios":"Placing a stray .md/.mdx/.json file directly in src/content/ rather than inside a named collection folder; leftover notes or template files dropped into the content root.","commonSituations":"Documentation or README files accidentally saved into src/content; misunderstanding that every entry must belong to a named collection subdirectory.","solutions":["Move the file into a collection subdirectory (src/content/<collection>/file.md)","Or relocate it outside src/content entirely (e.g. src/docs/)","Delete the file if it is stray"],"exampleFix":"# before\nsrc/content/README.md\n\n# after\nsrc/content/blog/contributing.md   (or move it out: src/docs/README.md)","handlingStrategy":"validation","validationCode":"// Lint: no content-type files directly under src/content\nimport { readdirSync, statSync } from 'node:fs';\nconst CONTENT_EXTS = ['.md', '.mdx', '.json', '.yaml', '.yml'];\nconst strays = readdirSync('src/content').filter(\n  (f) => statSync(`src/content/${f}`).isFile() && CONTENT_EXTS.some((ext) => f.endsWith(ext)),\n);\nif (strays.length > 0) throw new Error(`Files must live in a collection subdirectory: ${strays.join(', ')}`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep only collection subdirectories (and config files) inside src/content","Put notes/readme files outside the content root","Add the lint above to CI so stray files fail fast"],"tags":["astro","content-collections","types-generator","directory-structure"],"backgroundTag":"misplaced-content-file","analyzedSha":"e294953aa8aadd98d5be92e60a03037b05dbdfd4","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}