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

  1. Add session() middleware before csrf(): router.use(session(...), csrf())
  2. Verify middleware order — session() must appear earlier in the chain than csrf()
  3. 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

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


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/86f88cc0e141056b. Report an issue: GitHub.