What Causes This Error?
This error occurs when your middleware function doesn’t return a Response object or call next() to continue to the next handler. Middleware must do one or the other.
The Problem
// src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware((context, next) => {
// ❌ Does nothing - no return or next()
console.log('Request received');
});
The Fix
Call next() to Continue
// src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware((context, next) => {
console.log('Request received');
// ✅ Call next() to continue
return next();
});
Or Return a Response
// src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware((context, next) => {
// ✅ Return a Response directly
return new Response('Hello from middleware');
});
Common Scenarios
Authentication Middleware
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => {
const session = context.cookies.get('session');
// Check auth
if (!session && context.url.pathname.startsWith('/dashboard')) {
// ✅ Return redirect Response
return context.redirect('/login');
}
// ✅ Continue to page
return next();
});
Logging Middleware
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => {
const start = Date.now();
// ✅ Call next and capture response
const response = await next();
const duration = Date.now() - start;
console.log(`${context.request.method} ${context.url.pathname} - ${duration}ms`);
// ✅ Return the response
return response;
});
Modifying Response
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => {
// Get the response from the route
const response = await next();
// ✅ Modify and return
response.headers.set('X-Custom-Header', 'value');
return response;
});
Conditional Logic
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => {
// API routes
if (context.url.pathname.startsWith('/api/')) {
// Add API-specific headers
const response = await next();
response.headers.set('Content-Type', 'application/json');
return response;
}
// Regular pages
return next();
});
Setting Locals
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => {
// Set locals for use in pages
context.locals.user = { name: 'John' };
context.locals.timestamp = Date.now();
// ✅ Must still call next()
return next();
});
Error Handling
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => {
try {
return await next();
} catch (error) {
console.error('Error:', error);
// ✅ Return error response
return new Response('Server Error', { status: 500 });
}
});
Sequence Multiple Middleware
// src/middleware.ts
import { sequence } from 'astro:middleware';
import { auth } from './middleware/auth';
import { logging } from './middleware/logging';
// Each middleware must return Response or call next()
export const onRequest = sequence(auth, logging);
Async Operations
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => {
// ✅ Async operations are fine
const data = await fetchSomeData();
context.locals.data = data;
// ✅ Still need to return/call next
return next();
});
Quick Checklist
- Always
return next()orreturn new Response() - Use
await next()for async middleware - Return the response after
await next() - Use
context.redirect()for redirects - Set
context.localsbefore callingnext()