withastro/astro · error · AstroError

OnlyResponseCanBeReturned

OnlyResponseCanBeReturned

Error message

Route `${route}` returned a `${returnedValue}`. Only a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) can be returned from Astro files.

What it means

renderPage validates the value produced by a page component: allowed outcomes are a Response (redirect/404), a HeadAndContent wrapper whose content is a valid RenderTemplateResult, or a RenderTemplateResult itself (what the compiled .astro body normally produces). This site fires when the factory result is HeadAndContent but its content is not a render template, i.e. the page returned structured data where markup was required.

Solutions

  1. Return a Response for control flow: return new Response(null, { status: 404 }) or Astro.redirect(...)
  2. Otherwise return nothing and let the page template render
  3. Move pure data endpoints to a .js/.ts API route file instead of an .astro page

Example fix

// before
---
const post = await getPost(Astro.params.slug);
if (!post) return null;
---

// after
---
const post = await getPost(Astro.params.slug);
if (!post) return new Response(null, { status: 404 });
---
Defensive patterns

Strategy: type-guard

Validate before calling

// in wrappers that return page results, assert the shape
const result = await loadPageResult();
if (!(result instanceof Response)) {
  throw new Error('Page must return a Response or render its template');
}

Type guard

function isResponse(value: unknown): value is Response {
  return value instanceof Response;
}

Prevention

When it happens

Trigger: An .astro frontmatter returning a non-Response, non-template value that gets wrapped as head+content: return someObject, return null after a guard clause, or a layout/content combination whose content is data instead of template output.

Common situations: Treating .astro frontmatter like an endpoint (return data); early-return pattern 'if (!post) return;' with no value; returning the result of a helper that yields plain objects; porting pages from frameworks where returning strings/objects from pages is normal.

Related errors


AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18). Data as JSON: /api/errors/ab2c2d27036d56d8. Report an issue: GitHub.

Appendix: source

Thrown at packages/astro/src/runtime/server/render/astro/render.ts:323

}

async function callComponentAsTemplateResultOrResponse(
	result: SSRResult,
	componentFactory: AstroComponentFactory,
	props: any,
	children: any,
	route?: RouteData,
) {
	const factoryResult = await componentFactory(result, props, children);

	if (factoryResult instanceof Response) {
		return factoryResult;
	}
	// we check if the component we attempt to render is a head+content
	else if (isHeadAndContent(factoryResult)) {
		// we make sure that content is valid template result
		if (!isRenderTemplateResult(factoryResult.content)) {
			throw new AstroError({
				...AstroErrorData.OnlyResponseCanBeReturned,
				message: AstroErrorData.OnlyResponseCanBeReturned.message(
					route?.route,
					typeof factoryResult,
				),
				location: {
					file: route?.component,
				},
			});
		}

		// return the content
		return factoryResult.content;
	} else if (!isRenderTemplateResult(factoryResult)) {
		throw new AstroError({
			...AstroErrorData.OnlyResponseCanBeReturned,
			message: AstroErrorData.OnlyResponseCanBeReturned.message(route?.route, typeof factoryResult),
			location: {

View on GitHub (pinned to 52e6c34790)