remix-run/remix · error · Error
Middleware must return a Response or call next()
Error message
Middleware must return a Response or call next()
What it means
A middleware function must either return a Response (short-circuiting the chain) or call next() to delegate to downstream handlers. This error is thrown when the middleware returns undefined or another non-Response value and never called next().
Source
Thrown at packages/fetch-router/src/lib/middleware.ts:142
let nextPromise: Promise<Response> | undefined
let next: NextFunction = () => {
nextPromise = dispatch(i + 1)
return nextPromise
}
let response = await raceRequestAbort(Promise.resolve(fn(context, next)), context.request)
// If a response was returned, short-circuit the chain
if (response instanceof Response) {
return response
}
// If the middleware called next(), use the downstream response
if (nextPromise != null) {
return nextPromise
}
throw new Error('Middleware must return a Response or call next()')
}
return dispatch(0)
}
View on GitHub (pinned to 9696913134)
Solutions
- Add `return await next()` at the end of the middleware
- For short-circuiting (auth, redirects), return a Response: return redirect('/login')
- Check every code path (if/else, try/finally) returns a Response or calls next()
Example fix
// before
async function auth(ctx, next) {
if (!ctx.session) redirect('/login')
await next() // not returned
}
// after
async function auth(ctx, next) {
if (!ctx.session) return redirect('/login')
return next()
} Defensive patterns
Strategy: validation
Validate before calling
// ensure every path returns
const mw = async (ctx, next) => (condition ? new Response('ok') : next()) Type guard
const isResponse = (v: unknown): v is Response => v instanceof Response
Try / catch
try { return await middleware(ctx, next) } catch (e) { if (e instanceof Error && /Middleware must return/.test(e.message)) { return new Response('middleware error', { status: 500 }) } throw e } Prevention
- End middleware bodies with `return next()` or `return someResponse`
- Lint for middleware functions missing a return on some path
When it happens
Trigger: A middleware that forgets `return` on some path, does async work but returns nothing, or returns a mutated body/ non-Response object.
Common situations: Refactoring handlers into middleware and dropping the return statement; early-return guards (auth checks) that log or set state but neither respond nor call next().
Related errors
- next() called multiple times
- Context property name must be a string.
- Cannot install an empty context property name.
- Cannot install context property {formattedProperty} because
- Cannot install context property {formattedProperty} because
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/77e3f6c5b3b95a3c.
Report an issue: GitHub.