remix-run/react-router · error · Error

Cookie length will exceed browser maximum. Length: ${seriali

Error message

Cookie length will exceed browser maximum. Length: ${serializedCookie.length}

What it means

`createCookieSessionStorage().commitSession` serializes all session data into the cookie and rejects when the serialized cookie exceeds 4096 bytes (the practical browser cookie limit). Cookie-session storage trades backend-free simplicity for a hard size cap; exceeding it would silently truncate the session in the browser.

Source

Thrown at packages/react-router/lib/server-runtime/sessions/cookieStorage.ts:56

  Data,
  FlashData
> {
  let cookie = isCookie(cookieArg)
    ? cookieArg
    : createCookie(cookieArg?.name || "__session", cookieArg);

  warnOnceAboutSigningSessionCookie(cookie);

  return {
    async getSession(cookieHeader, options) {
      return createSession(
        (cookieHeader && (await cookie.parse(cookieHeader, options))) || {},
      );
    },
    async commitSession(session, options) {
      let serializedCookie = await cookie.serialize(session.data, options);
      if (serializedCookie.length > 4096) {
        throw new Error(
          "Cookie length will exceed browser maximum. Length: " +
            serializedCookie.length,
        );
      }
      return serializedCookie;
    },
    async destroySession(_session, options) {
      return cookie.serialize("", {
        ...options,
        maxAge: undefined,
        expires: new Date(0),
      });
    },
  };
}

View on GitHub (pinned to 1fd704a7da)

Solutions

  1. Move large/per-user data to a server-side store and keep only a session id in the cookie (use `createSessionStorage` with a custom adapter backed by Redis/DB).
  2. Clear flash data before commit and trim unused fields.
  3. Reduce cookie options (long `SameSite`, `Domain`, etc.) and shorten the cookie name.
  4. If you need signed cookies, account for the signature size in your 4096 budget.

Example fix

// before
export const sessionStorage = createCookieSessionStorage({ cookie: { name: '__session' } });
// session.data grows until > 4096 bytes -> throws on commit

// after
export const sessionStorage = createSessionStorage({
  cookie: { name: 'sid', secrets: ['...'] },
  createData: (data, expires) => redis.set(...),
  readData: (id) => redis.get(id),
  updateData: (id, data, expires) => redis.set(...),
  deleteData: (id) => redis.del(id),
});
Defensive patterns

Strategy: validation

Validate before calling

async function safeCommit(storage: SessionStorage, session: Session, max = 4096) {
  const cookie = await storage.commitSession(session);
  if (cookie.length > max) throw new Error(`Cookie too large: ${cookie.length}`);
  return cookie;
}
// or, proactively estimate before commit:
function estimateCookieBytes(data: unknown) {
  return JSON.stringify(data).length + 200; // +overhead/signature headroom
}

Try / catch

try {
  headers.append('Set-Cookie', await sessionStorage.commitSession(session));
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Cookie length will exceed')) {
    // spill to server-side store, keep only an id in the cookie
    session.id = await persist(session.data);
    session.data = {};
    headers.append('Set-Cookie', await sessionStorage.commitSession(session));
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `commitSession(session)` on a session whose serialized form (data + cookie name + options like `Max-Age`, `Path`, signed HMAC for secret cookies) is over 4096 bytes.

Common situations: Storing growing per-user data (flash messages, cart contents, JSON blobs) in the session; stacking multiple flash messages; a signed cookie where the HMAC signature alone consumes hundreds of bytes; adding many cookie options that bloat the header.

Related errors


AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12). Data as JSON: /api/errors/17573490aa65f297. Report an issue: GitHub.