withastro/astro · warning

Entry ${collection} → ${lookupId} was not found.

Error message

Entry ${collection} → ${lookupId} was not found.

What it means

getEntry(collection, lookupId) found the collection but no entry with that id; Astro logs this warning and returns undefined. Note the API accepts ids and, for content entries, slugs — passing an object as the identifier is a separate hard error above this branch, but a stale or wrong string only yields undefined plus this warning, which frequently surfaces later as a TypeError on the undefined result.

Source

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

		if (collection in liveCollections) {
			throw new AstroError({
				...AstroErrorData.UnknownContentCollectionError,
				message: `Collection "${collection}" is a live collection. Use getLiveEntry() instead of getEntry().`,
			});
		}
		if (typeof lookupId === 'object') {
			throw new AstroError({
				...AstroErrorData.UnknownContentCollectionError,
				message: `The entry identifier must be a string. Received object.`,
			});
		}
		const store = await globalDataStore.get();

		if (await store.hasCollection(collection)) {
			const entry = await store.get<DataEntry>(collection, lookupId);
			if (!entry) {
				logger.warn('content', `Entry ${collection} → ${lookupId} was not found.`);
				return;
			}

			// @ts-expect-error	virtual module
			const { default: imageAssetMap } = await import('astro:asset-imports');
			const data = resolveEntryData(entry, imageAssetMap);
			const result = {
				...entry,
				data,
				collection,
			} as DataEntryResult | ContentEntryResult;
			// TODO: remove in Astro 8
			warnForPropertyAccess(
				logger,
				result.data,
				'slug',
				`[content] Attempted to access deprecated property on "${collection}" entry.\nThe "slug" property is no longer automatically added to entries. Please use the "id" property instead.`,
			);

View on GitHub (pinned to e294953aa8)

Solutions

  1. Use the current id/slug — run astro sync and rely on generated types to flag stale references at compile time
  2. Guard the undefined result before accessing properties
  3. For dynamic routes, derive lookups from getStaticPaths so the ids always exist

Example fix

// before
const post = await getEntry('blog', 'old-slug');
const { data } = post; // TypeError when undefined

// after
const post = await getEntry('blog', 'new-slug');
if (!post) return null;
const { data } = post;
Defensive patterns

Strategy: type-guard

Validate before calling

// For dynamic routes, validate ids against the store before lookup
const entries = await getCollection('blog');
const ids = new Set(entries.map((e) => e.id));
if (!ids.has(lookupId)) {
  return Astro.redirect('/404');
}

Type guard

type ContentEntryLike = { id: string; slug: string };
function isEntry<T extends ContentEntryLike>(entry: T | undefined): entry is T {
  return entry !== undefined;
}
// usage:
const post = await getEntry('blog', slug);
if (!isEntry(post)) return Astro.redirect('/404');

Prevention

When it happens

Trigger: Looking up a hard-coded slug/id that was renamed or deleted; confusing data-entry ids with content-entry slugs; entries whose frontmatter slug differs from the filename so the wrong key is passed.

Common situations: Renaming files or slugs breaking getEntry calls scattered through pages; lookups driven by URL params or CMS data; dynamic routes whose param values drift from actual entry ids.

Related errors


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