remix-run/remix · critical · Error
csrf middleware requires session() middleware to run before
Error message
csrf middleware requires session() middleware to run before it
What it means
The csrf() middleware stores and verifies CSRF tokens in the user session, so it requires the session() middleware to have run earlier in the request pipeline. At request time it checks context.get(Session); if no session is present it throws this error rather than silently skipping CSRF protection.
Source
Thrown at packages/csrf-middleware/src/lib/csrf.ts:134
/**
* Session-backed CSRF protection middleware.
*
* This middleware requires the session middleware to run before it.
*
* @param options CSRF options
* @returns CSRF middleware
*/
export function csrf(options: CsrfOptions = {}): Middleware {
let safeMethods = options.safeMethods ?? defaultSafeMethods
let tokenKey = options.tokenKey ?? '_csrf'
let fieldName = options.fieldName ?? '_csrf'
let headerNames = options.headerNames ?? defaultTokenHeaderNames
let allowMissingOrigin = options.allowMissingOrigin ?? true
return async (context, next) => {
if (context.get(Session) == null) {
throw new Error('csrf middleware requires session() middleware to run before it')
}
let expectedToken = getCsrfToken(context, tokenKey)
if (isSafeMethod(context.method, safeMethods)) {
return next()
}
let validOrigin = await validateRequestOrigin(
context,
options.origin,
allowMissingOrigin,
context.url.origin,
)
if (!validOrigin) {
return getErrorResponse(options, 'invalid-origin', context)
}
View on GitHub (pinned to 9696913134)
Solutions
- Add session() middleware before csrf(): router.use(session(...), csrf())
- Verify middleware order — session() must appear earlier in the chain than csrf()
- Check that any conditional middleware registration always includes session() when csrf() is enabled
Example fix
// before router.use(csrf()) // after router.use(session(sessionOptions), csrf())
Defensive patterns
Strategy: validation
Validate before calling
const handler = session(sessionOptions).wrap?.(csrf()) // or:
// verify at setup: router.use(session(...)); router.use(csrf())
// runtime guard before csrf logic:
if (context.get(Session) == null) throw new Error('configure session() before csrf()') Type guard
import { Session } from 'remix'
const hasSession = (ctx: Request['context']) => ctx.get(Session) != null Try / catch
try { await csrfHandler(context, next) } catch (e) { if (e instanceof Error && e.message.includes('session() middleware')) { /* fix middleware order */ } throw e } Prevention
- Always register session() before csrf() in one place
- Add a smoke test that any csrf-enabled route also has session middleware
When it happens
Trigger: Registering csrf() without session() in the middleware chain: e.g. router.use(csrf()) with no prior session() middleware, or ordering csrf() before session() so context.get(Session) is null when csrf runs.
Common situations: Adding csrf() to an existing app that never set up sessions; middleware ordering mistakes where session() runs after csrf(); tree-shaking or conditional registration that accidentally drops session().
Related errors
- Session is not started. Use session() middleware before csrf
- invalid bypass pattern ${JSON.stringify(pattern)}: path must
- MySQL database + method + () requires config-based construc
- MySQL database config requires a database name
- hasManyThrough relation is missing through metadata
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/86f88cc0e141056b.
Report an issue: GitHub.