{"record":{"id":"3bb59f3bf6da7839","repo":"withastro/astro","slug":"middlewarenodataornextcalled","errorCode":"MiddlewareNoDataOrNextCalled","errorMessage":"Make sure your middleware returns a `Response` object, either directly or by returning the `Response` from calling the `next` function.","messagePattern":"Make sure your middleware returns a `Response` object, either directly or by returning the `Response` from calling the `next` function\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/middleware/callMiddleware.ts","lineNumber":96,"sourceCode":"\t\t\t\treturn value;\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * Here we handle the case where `next` was called and returned nothing.\n\t\t\t\t */\n\t\t\t\tif (responseFunctionPromise) {\n\t\t\t\t\treturn responseFunctionPromise;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new AstroError(AstroErrorData.MiddlewareNotAResponse);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (typeof value === 'undefined') {\n\t\t\t/**\n\t\t\t * There might be cases where `next` isn't called and the middleware **must** return\n\t\t\t * something.\n\t\t\t *\n\t\t\t * If not thing is returned, then we raise an Astro error.\n\t\t\t */\n\t\t\tthrow new AstroError(AstroErrorData.MiddlewareNoDataOrNextCalled);\n\t\t} else if (value instanceof Response === false) {\n\t\t\tthrow new AstroError(AstroErrorData.MiddlewareNotAResponse);\n\t\t} else {\n\t\t\t// Middleware did not call resolve and returned a value\n\t\t\treturn value;\n\t\t}\n\t});\n}\n","sourceCodeStart":78,"sourceCodeEnd":105,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/core/middleware/callMiddleware.ts#L78-L105","documentation":"callMiddleware throws AstroErrorData.MiddlewareNoDataOrNextCalled when the middleware neither called next() nor returned anything. Astro requires exactly one of those two outcomes per request — the middleware must either delegate to the rest of the pipeline or produce a Response itself. This error means some code path fell through doing neither.","triggerScenarios":"An auth middleware with `if (authorized) return next();` but no else branch; an async middleware whose early return was removed during refactoring; a middleware returning undefined from a conditional block (e.g. inside a switch) on the deny path.","commonSituations":"Adding conditional logic to existing middleware and forgetting the negative path; renaming or refactoring that drops a `return`; TypeScript not flagging it because the handler type permits undefined at runtime.","solutions":["Make every branch end in `return next()` or `return <Response>`","Add a final `return next();` at the bottom of the middleware as a safe default","Type the middleware with defineMiddleware so return paths are easier to audit; add a unit test hitting the deny path"],"exampleFix":"// before — deny path returns undefined\nexport const onRequest = async (context, next) => {\n  if (context.cookies.get('session')) return next();\n};\n\n// after\nexport const onRequest = async (context, next) => {\n  if (!context.cookies.get('session')) return context.redirect('/login', 302);\n  return next();\n};","handlingStrategy":"validation","validationCode":"export const onRequest = async (context, next) => {\n  if (!isAuthorized(context)) return context.redirect('/login', 302); // deny path returns a Response\n  return next(); // fall-through path delegates\n};","typeGuard":null,"tryCatchPattern":null,"preventionTips":["End every branch with `return next()` or `return <Response>`","Add a final `return next();` as the last statement of each middleware","Write tests for the deny path — it is the branch that usually falls through"],"tags":["middleware","next-not-called","missing-return","control-flow"],"backgroundTag":"middleware-next-not-called","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}