withastro/astro · error · AstroError

MiddlewareNotAResponse

MiddlewareNotAResponse

Error message

Any data returned from middleware must be a valid `Response` object.

What it means

callMiddleware enforces the middleware contract: a middleware that calls next() may return nothing (the response from next is used) or must return a Response instance. This branch throws AstroErrorData.MiddlewareNotAResponse when next() was called and the middleware returned a defined value that fails `value instanceof Response` — a plain object, string, or a Response created in another runtime/Realm (e.g. a node-fetch or cross-realm Response).

Solutions

  1. Return the Response you got: `const res = await next(); return res;`
  2. Build a real Response when transforming: return new Response(body, { status, headers })
  3. Remove fetch polyfills from server code so instanceof checks use the global Response

Example fix

// before
export const onRequest = async (context, next) => {
  const response = await next();
  if (!response.ok) return { status: 500 };
  return response;
};

// after
export const onRequest = async (context, next) => {
  const response = await next();
  if (!response.ok) return new Response('error', { status: 500 });
  return response;
};
Defensive patterns

Strategy: validation

Validate before calling

const result = await next();
if (!(result instanceof Response)) {
  throw new TypeError('Middleware returned a non-Response value after next()');
}
return result;

Type guard

const isResponse = (value: unknown): value is Response => value instanceof Response;

Prevention

When it happens

Trigger: A middleware that does `const res = await next(); return { ...res }` or returns a status object like { status: 500 }; returning a Response produced by a fetch polyfill or another Realm so the instanceof check against the global Response fails.

Common situations: Copying Express middleware patterns that return plain result objects; using node-fetch or an older undici alongside the global fetch in the same process; middleware returning response.json() or a mutated copy of headers instead of the Response itself.

Related errors


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

Appendix: source

Thrown at packages/astro/src/core/middleware/callMiddleware.ts:76

	};

	const middlewarePromise = onRequest(apiContext, next);

	return await Promise.resolve(middlewarePromise).then(async (value) => {
		// first we check if `next` was called
		if (nextCalled) {
			/**
			 * Then we check if a value is returned. If so, we need to return the value returned by the
			 * middleware.
			 * e.g.
			 * ```js
			 * 	const response = await next();
			 * 	const new Response(null, { status: 500, headers: response.headers });
			 * ```
			 */
			if (typeof value !== 'undefined') {
				if (value instanceof Response === false) {
					throw new AstroError(AstroErrorData.MiddlewareNotAResponse);
				}
				return value;
			} else {
				/**
				 * Here we handle the case where `next` was called and returned nothing.
				 */
				if (responseFunctionPromise) {
					return responseFunctionPromise;
				} else {
					throw new AstroError(AstroErrorData.MiddlewareNotAResponse);
				}
			}
		} else if (typeof value === 'undefined') {
			/**
			 * There might be cases where `next` isn't called and the middleware **must** return
			 * something.
			 *
			 * If not thing is returned, then we raise an Astro error.

View on GitHub (pinned to 52e6c34790)