{"record":{"id":"46e9d118596ae9df","repo":"withastro/astro","slug":"id-must-be-a-non-empty-string","errorCode":null,"errorMessage":"ID must be a non-empty string","messagePattern":"ID must be a non-empty string","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/content/mutable-data-store.ts","lineNumber":342,"sourceCode":"\t\t\t// If there are pending writes, we need to write again to ensure we flush the latest data.\n\t\t\tif (this.#pending.has(fileKey)) {\n\t\t\t\tthis.#pending.delete(fileKey);\n\t\t\t\t// Call ourself recursively to write the file again\n\t\t\t\tawait this.#writeFileAtomic(filePath, data, depth + 1);\n\t\t\t}\n\t\t}\n\t}\n\n\tscopedStore(collectionName: string): DataStore {\n\t\treturn {\n\t\t\tget: <TData extends Record<string, unknown> = Record<string, unknown>>(key: string) =>\n\t\t\t\tthis.get<DataEntry<TData>>(collectionName, key),\n\t\t\tentries: () => this.entries(collectionName),\n\t\t\tvalues: () => this.values(collectionName),\n\t\t\tkeys: () => this.keys(collectionName),\n\t\t\tset: ({ id: key, data, body, filePath, deferredRender, digest, rendered, assetImports }) => {\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(`ID must be a non-empty string`);\n\t\t\t\t}\n\t\t\t\tconst id = String(key);\n\t\t\t\tif (digest) {\n\t\t\t\t\tconst existing = this.get<DataEntry>(collectionName, id);\n\t\t\t\t\tif (existing && existing.digest === digest) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst foundAssets = new Set<string>(assetImports);\n\t\t\t\t// Check for image imports in the data. These will have been prefixed during schema parsing\n\t\t\t\tforEach(data, (_, val) => {\n\t\t\t\t\tif (typeof val === 'string' && val.startsWith(IMAGE_IMPORT_PREFIX)) {\n\t\t\t\t\t\tconst src = val.replace(IMAGE_IMPORT_PREFIX, '');\n\t\t\t\t\t\tfoundAssets.add(src);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tconst entry: DataEntry = {","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/content/mutable-data-store.ts#L324-L360","documentation":"Thrown as a plain Error (no AstroError code) from the scoped store's set() method when the provided id (key) is falsy (undefined, null, '', 0, false). Every content entry must have a non-empty string identifier, so a missing id is treated as a loader bug.","triggerScenarios":"A collection loader calls context.store.set({ id: someValue, data }) where someValue is undefined/empty — e.g. deriving id from a missing field, or passing an object whose id property is absent.","commonSituations":"Custom loader reading a data file whose rows are missing the id field; slug/id generation returning empty for edge-case filenames; glob loader generateId returning ''; conditional id logic that yields undefined.","solutions":["In your loader, validate the id before calling store.set: if (!id) throw ... or skip the entry.","Ensure generateId (glob loader) always returns a non-empty string.","Inspect the source data for rows/objects lacking an id and fix or filter them.","Default to a derived slug when the field is absent."],"exampleFix":"// before - custom loader\nfor (const row of rows) {\n  context.store.set({ id: row.key, data: row });\n}\n// after\nfor (const row of rows) {\n  const id = row.key ?? slugify(row.title);\n  if (!id) continue;\n  context.store.set({ id, data: row });\n}","handlingStrategy":"validation","validationCode":"function setEntry(store: DataStore, id: unknown, data: Record<string, unknown>) {\n  if (typeof id !== 'string' || id.length === 0) throw new TypeError('id must be non-empty string');\n  store.set({ id, data });\n}","typeGuard":"const isNonEmptyString = (v: unknown): v is string => typeof v === 'string' && v.length > 0;","tryCatchPattern":null,"preventionTips":["Always validate id before store.set in custom loaders.","Ensure generateId (glob loader) returns a non-empty string for every input.","Filter or fail loudly on data rows lacking an id."],"tags":["content-collections","data-store","loader","validation"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}