withastro/astro · error · AstroError

RenderUndefinedEntryError

RenderUndefinedEntryError

Error message

Attempted to render an undefined content collection entry.

What it means

renderEntry() backs the public render(entry) from astro:content and throws this error when it receives a falsy entry. getEntry and getCollection lookups return undefined for ids/slugs that do not exist, so rendering without a check turns a missing entry into this explicit error rather than a cryptic crash inside the renderer.

Solutions

  1. Check the entry before rendering and return a 404 or redirect: if (!post) return Astro.redirect('/404').
  2. Verify the identifier you pass matches how entries are keyed: id for data entries, slug for content entries.
  3. For dynamic routes, generate params from getCollection()/getStaticPaths so only existing entries render.

Example fix

// before
const post = await getEntry('blog', params.slug);
const { Content } = await render(post);

// after
const post = await getEntry('blog', params.slug);
if (!post) return Astro.redirect('/404');
const { Content } = await render(post);
Defensive patterns

Strategy: type-guard

Validate before calling

// Always resolve and check before rendering
const post = params.slug ? await getEntry('blog', params.slug) : undefined;
if (!post) return Astro.redirect('/404');
const { Content } = await render(post);

Type guard

import type { CollectionEntry } from 'astro:content';

function isRenderableEntry<E>(entry: E | undefined | null): entry is E {
  return entry != null;
}

// usage
if (isRenderableEntry(post)) await render(post);

Prevention

When it happens

Trigger: Calling render(entry) where entry came from getEntry('blog', id) and no entry with that id/slug exists; dynamic routes ([...slug].astro) where params.slug matches no entry; entries removed or renamed between data sync and render.

Common situations: Dynamic routes without a getStaticPaths guard; typo'd slug from a URL parameter; content deleted during a CMS migration while pages still reference it; code assuming getEntry throws on miss instead of returning undefined.

Related errors


AI-assisted analysis of withastro/astro@e294953aa8 (2026-09-09). Data as JSON: /api/errors/9e05fa148128ce87. Report an issue: GitHub.

Appendix: source

Thrown at packages/astro/src/content/runtime.ts:626

		const resolved = resolveImageAtPath(src, fileName, imageAssetMap);
		if (resolved !== undefined) {
			result = setAtPathCopying(result, path, resolved);
		}
	}
	return result;
}

export function resolveEntryData<T extends Record<string, unknown>>(
	entry: DataEntry<T>,
	imageAssetMap?: Map<string, ImageMetadata>,
): T {
	return updateImageReferencesInData(entry.data, entry.filePath, imageAssetMap, entry.imageImports);
}

export function createRenderEntry({ logger }: { logger: AstroLogger }) {
	return async function renderEntry(entry: DataEntry) {
		if (!entry) {
			throw new AstroError(AstroErrorData.RenderUndefinedEntryError);
		}
		recordContentEntryRender(entry.filePath);

		if (entry.deferredRender) {
			try {
				// @ts-expect-error	virtual module
				const { default: contentModules } = await import('astro:content-module-imports');
				const renderEntryImport = contentModules.get(entry.filePath);
				return render({
					collection: '',
					id: entry.id,
					renderEntryImport,
				});
			} catch (e) {
				logger.error('content', `${e}`);
			}
		}

View on GitHub (pinned to e294953aa8)