komal.nakrani
Browse Themes
ThemesCategoriesDocsBlogTips & Tricks
Routing••By Komal Nakrani

Fix: The Endpoint Did Not Return a Response in Astro

Astro's 'The endpoint did not return a Response' means a GET or POST handler returned nothing or an object. Return Response.json() on every path.

#Astro#Errors#Endpoints

Astro shows “The endpoint did not return a Response” when a handler in a .ts or .js file under src/pages/ (an endpoint) returns something other than a Response. The message: “An endpoint must return either a Response, or a Promise that resolves with a Response.” Older Astro versions accepted { body: ... } objects; current versions don’t. Return new Response(...) or Response.json(...) from every code path.

Key Takeaways

  • Endpoint handlers (GET, POST, …) must return a Response.
  • return { body: JSON.stringify(data) } is the old format and fails now.
  • Use Response.json(data) for JSON, new Response(text, { headers }) for anything else.
  • Check if branches: a path that returns nothing triggers the error.

Old format, which fails

// src/pages/api/posts.json.ts
export async function GET() {
  const posts = await getCollection('blog');
  return { body: JSON.stringify(posts.map((p) => p.id)) };
}

Current format

// src/pages/api/posts.json.ts
import type { APIRoute } from 'astro';
import { getCollection } from 'astro:content';

export const GET: APIRoute = async () => {
  const posts = await getCollection('blog');
  return Response.json(posts.map((p) => ({ id: p.id, title: p.data.title })));
};

For text or XML:

export const GET: APIRoute = () =>
  new Response('User-agent: *\nAllow: /\n', {
    headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  });

Typing the handler as APIRoute makes TypeScript flag a wrong return value before you build.

Branches that return nothing

export const POST: APIRoute = async ({ request }) => {
  const data = await request.formData();
  if (!data.get('email')) {
    return new Response('Email required', { status: 400 });
  }
  await subscribe(String(data.get('email')));
  // missing return
};

Add return new Response(null, { status: 204 }); or a redirect: return Response.redirect(new URL('/thanks/', request.url), 303);.

Static vs on-demand endpoints

In a static build, GET endpoints run once and their output is written as a file, which is how robots.txt and sitemaps are generated. POST and other methods only run on demand, which needs export const prerender = false and an adapter; without one you’ll hit Cannot use server-side rendering without an adapter.

The Astro routing guide covers endpoints with dynamic params, and the endpoints docs list everything a handler receives.

FAQ

Can an endpoint return a stream?

Yes. Pass a ReadableStream as the Response body, on demand.

How do I name the output file of a static endpoint?

By the file name: src/pages/feed.json.ts builds /feed.json.