withastro/astro · error · AstroError
MiddlewareNotAResponse
MiddlewareNotAResponse
Error message
Any data returned from middleware must be a valid `Response` object.
What it means
Thrown when middleware called next() and then returned a defined value that is not a Response instance. After awaiting next() the middleware may return next()'s Response or a new Response, but returning any other type (object, string, number) is rejected because the runtime must emit an HTTP Response.
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 d081033d5f)
Solutions
- Wrap returned data in a Response: `return new Response(JSON.stringify(data), { headers: { 'content-type': 'application/json' } })`.
- If you only meant to pass through, return the result of next(): `return await next()`.
- Return undefined after calling next() to let the downstream Response propagate.
Example fix
// before
export const onRequest = async (ctx, next) => {
await next();
return { ok: true };
};
// after
export const onRequest = async (ctx, next) => {
await next();
return Response.json({ ok: true });
}; Defensive patterns
Strategy: type-guard
Validate before calling
// Ensure middleware returns a Response or undefined (after next).
export const onRequest = async (ctx, next) => {
await next();
const payload = { ok: true };
return Response.json(payload); // Response, not raw object
}; Type guard
function isResponse(v: unknown): v is Response {
return v instanceof Response;
} Try / catch
try {
await callMiddleware(handler, ctx, render);
} catch (e) {
if (e instanceof Error && /valid .Response./i.test(e.message)) {
// middleware returned a non-Response; fix the return
}
throw e;
} Prevention
- After calling next(), return either next()'s result or a new Response.
- Wrap data in Response.json() or new Response().
- Add a return-type annotation of Response | Promise<Response> to middleware.
When it happens
Trigger: A middleware does `await next()` and then `return someObject` or `return 'ok'` where the value is not a Response. The check `value instanceof Response === false` at line 76 of callMiddleware.ts fires for the nextCalled + defined value branch.
Common situations: Returning a JSON object or status string instead of `Response.json(...)`; returning locals or a payload by mistake; partial refactor where a helper that used to return a Response now returns data.
Related errors
- MiddlewareNoDataOrNextCalled
- ResponseSentError
- StaticClientAddressNotAvailable
- ForbiddenRewrite
- RedirectWithNoLocation
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/1e884bb44ef7ddbc.
Report an issue: GitHub.