How It Works Features Pricing Blog Error Guides
Log In Start Free Trial
Express · JavaScript

Fix Error: req.session is undefined — session middleware not initialized in Express

This error occurs when you access req.session before the express-session middleware has been registered, or when the session store fails to connect. Fix it by ensuring express-session is registered before your routes and that the session store connection is healthy.

Reading the Stack Trace

TypeError: Cannot read properties of undefined (reading 'userId') at authenticateUser (/app/src/middleware/auth.js:8:24) at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) at next (/app/node_modules/express/lib/router/route.js:144:13) at Route.dispatch (/app/node_modules/express/lib/router/route.js:114:3) at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) at /app/node_modules/express/lib/router/index.js:284:15 at Function.process_params (/app/node_modules/express/lib/router/index.js:346:12) at next (/app/node_modules/express/lib/router/index.js:280:10) at expressInit (/app/node_modules/express/lib/middleware/init.js:40:5) at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)

Here's what each line means:

Common Causes

1. Session middleware registered after routes

The express-session middleware is added after the route definitions, so routes execute before sessions are available.

const express = require('express');
const session = require('express-session');
const app = express();

// Routes registered before session middleware
app.get('/dashboard', (req, res) => {
  res.json({ user: req.session.userId });
});

app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));

2. Session store connection failure

The session store (e.g., Redis, MongoDB) is unreachable, so express-session cannot initialize sessions on incoming requests.

const session = require('express-session');
const RedisStore = require('connect-redis').default;
const { createClient } = require('redis');

const redisClient = createClient({ url: 'redis://wrong-host:6379' });
// redisClient.connect() never called or fails silently

app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: 'keyboard cat'
}));

3. Missing express-session dependency

The express-session package is not installed, so the require call fails or the middleware is never added.

// package.json does not include express-session
const session = require('express-session'); // throws MODULE_NOT_FOUND

The Fix

Move the express-session middleware registration above all route definitions so that req.session is populated before any route handler accesses it. Also add a guard to handle unauthenticated requests gracefully.

Before (broken)
const express = require('express');
const session = require('express-session');
const app = express();

app.get('/dashboard', (req, res) => {
  res.json({ user: req.session.userId });
});

app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));

app.listen(3000);
After (fixed)
const express = require('express');
const session = require('express-session');
const app = express();

// Session middleware BEFORE routes
app.use(session({
  secret: process.env.SESSION_SECRET || 'keyboard cat',
  resave: false,
  saveUninitialized: false,
  cookie: { secure: process.env.NODE_ENV === 'production', maxAge: 86400000 }
}));

app.get('/dashboard', (req, res) => {
  if (!req.session.userId) {
    return res.status(401).json({ error: 'Not authenticated' });
  }
  res.json({ user: req.session.userId });
});

app.listen(3000);

Testing the Fix

const request = require('supertest');
const express = require('express');
const session = require('express-session');

function createApp() {
  const app = express();
  app.use(session({ secret: 'test-secret', resave: false, saveUninitialized: false }));
  app.get('/dashboard', (req, res) => {
    if (!req.session.userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    res.json({ user: req.session.userId });
  });
  return app;
}

describe('GET /dashboard', () => {
  it('returns 401 when session has no userId', async () => {
    const res = await request(createApp()).get('/dashboard');
    expect(res.status).toBe(401);
    expect(res.body.error).toBe('Not authenticated');
  });

  it('req.session is defined when middleware is registered', async () => {
    const res = await request(createApp()).get('/dashboard');
    expect(res.status).not.toBe(500);
  });
});

Run your tests:

npx jest --testPathPattern=session

Pushing Through CI/CD

git checkout -b fix/express-session-error,git add src/app.js src/__tests__/session.test.js,git commit -m "fix: register session middleware before routes",git push origin fix/express-session-error

Your CI config should look something like this:

name: CI
on:
  pull_request:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npx jest --coverage
      - run: npm run lint

The Full Manual Process: 18 Steps

Here's every step you just went through to fix this one bug:

  1. Notice the error alert or see it in your monitoring tool
  2. Open the error dashboard and read the stack trace
  3. Identify the file and line number from the stack trace
  4. Open your IDE and navigate to the file
  5. Read the surrounding code to understand context
  6. Reproduce the error locally
  7. Identify the root cause
  8. Write the fix
  9. Run the test suite locally
  10. Fix any failing tests
  11. Write new tests covering the edge case
  12. Run the full test suite again
  13. Create a new git branch
  14. Commit and push your changes
  15. Open a pull request
  16. Wait for code review
  17. Merge and deploy to production
  18. Monitor production to confirm the error is resolved

Total time: 30-60 minutes. For one bug.

Or Let bugstack Fix It in Under 2 minutes

Every step above? bugstack does it automatically.

Step 1: Install the SDK

npm install bugstack-sdk

Step 2: Initialize

const { initBugStack } = require('bugstack-sdk')

initBugStack({ apiKey: process.env.BUGSTACK_API_KEY })

Step 3: There is no step 3.

bugstack handles everything from here:

  1. Captures the stack trace and request context
  2. Pulls the relevant source files from your GitHub repo
  3. Analyzes the error and understands the code context
  4. Generates a minimal, verified fix
  5. Runs your existing test suite
  6. Pushes through your CI/CD pipeline
  7. Deploys to production (or opens a PR for review)

Time from error to fix deployed: Under 2 minutes.

Human involvement: zero.

Try bugstack Free →

No credit card. 5-minute setup. Cancel anytime.

Deploying the Fix (Manual Path)

  1. Run the test suite locally to confirm session is available in route handlers.
  2. Open a pull request with the middleware reorder.
  3. Wait for CI checks to pass on the PR.
  4. Have a teammate review and approve the PR.
  5. Merge to main and verify session behavior in staging before promoting to production.

Frequently Asked Questions

BugStack verifies that req.session is defined in all route handlers, runs your test suite, and confirms no session-dependent flows are broken before marking it safe.

Every fix is delivered as a pull request with full CI validation. Your team reviews and approves before anything reaches production.

Yes. Express executes middleware in the order it is registered. If a route is defined before session middleware, req.session will be undefined when that route handles a request.

Yes, cookie-session stores data in the cookie itself. It works well for small session payloads but is limited by cookie size (typically 4KB). For larger sessions, use express-session with a store like Redis.