withastro/astro · error · AstroError

MiddlewareNoDataOrNextCalled

MiddlewareNoDataOrNextCalled

Error message

Make sure your middleware returns a `Response` object, either directly or by returning the `Response` from calling the `next` function.

What it means

Thrown when middleware neither called next() nor returned any value. A middleware must do at least one: call next() to delegate to the next handler/page, or return a Response. Returning undefined without calling next leaves Astro with nothing to render.

Source

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

				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.
			 */
			throw new AstroError(AstroErrorData.MiddlewareNoDataOrNextCalled);
		} else if (value instanceof Response === false) {
			throw new AstroError(AstroErrorData.MiddlewareNotAResponse);
		} else {
			// Middleware did not call resolve and returned a value
			return value;
		}
	});
}

View on GitHub (pinned to d081033d5f)

Solutions

  1. End every middleware with `return next()` unless intentionally returning a Response.
  2. Audit conditional branches to ensure each path either returns a Response or calls next.
  3. Use defineMiddleware() so TypeScript guides the return type.

Example fix

// before
export const onRequest = async (ctx, next) => {
  ctx.locals.time = Date.now();
};

// after
export const onRequest = async (ctx, next) => {
  ctx.locals.time = Date.now();
  return next();
};
Defensive patterns

Strategy: validation

Validate before calling

// Every code path must call next() or return a Response.
export const onRequest = async (ctx, next) => {
  ctx.locals.t = Date.now();
  return next(); // mandatory terminator
};

Type guard

// Middleware must yield a Response or delegate via next.
function middlewareTerminates(value: unknown, nextCalled: boolean): boolean {
  return nextCalled || value instanceof Response;
}

Try / catch

try {
  await callMiddleware(handler, ctx, render);
} catch (e) {
  if (e instanceof Error && /returns a .Response./i.test(e.message)) {
    // middleware forgot to return next(); add it
  }
  throw e;
}

Prevention

When it happens

Trigger: A middleware that does work (sets locals, logs) and ends without `return next()` or any return statement. The `else if (typeof value === 'undefined')` branch at line 96 of callMiddleware.ts catches this.

Common situations: Forgetting to add `return next()` after early logic; a conditional branch that forgets to call next in the fall-through case; refactoring a handler and dropping the final next call.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/3bb59f3bf6da7839. Report an issue: GitHub.