Skip to content

fix: serialize Map and Buffer in Redis ISR handler (fixes #15)#29

Merged
mrjasonroy merged 3 commits intomainfrom
fix/issue-15-segmentdata-map-serialization
Feb 24, 2026
Merged

fix: serialize Map and Buffer in Redis ISR handler (fixes #15)#29
mrjasonroy merged 3 commits intomainfrom
fix/issue-15-segmentdata-map-serialization

Conversation

@mrjasonroy
Copy link
Copy Markdown
Owner

Summary

  • Fixes ISR cache-handler: r.segmentData.get is not a function #15r.segmentData.get is not a function when using the Redis ISR cache handler with Next.js 16 APP_PAGE entries
  • Next.js 16 stores segmentData as a Map<string, Buffer> and rscData as a Buffer on APP_PAGE cache entries. Plain JSON.stringify converts Maps to {} and loses Buffer identity, so on deserialization segmentData.get() throws
  • Adds custom jsonReplacer/jsonReviver to the Redis ISR handler that preserve Map and Buffer types through the serialization round-trip
  • Also adds APP_PAGE, APP_ROUTE, PAGES, and REDIRECT to the CacheValue type union to match the full Next.js 16 cache entry vocabulary

Changes

  • packages/cache-handler/src/handlers/redis.tsjsonReplacer / jsonReviver functions; set() uses replacer, get() uses reviver. Also handles backward-compat with Node's native Buffer.toJSON() format for entries stored before this fix
  • packages/cache-handler/src/types.ts — adds missing cache value kinds (APP_PAGE, APP_ROUTE, PAGES, REDIRECT)
  • packages/cache-handler/src/handlers/redis.test.ts — new test suite covering APP_PAGE with segmentData Map + rscData Buffer round-trip, empty/undefined segmentData, APP_ROUTE with Buffer body, backward compat with old Buffer JSON format, and existing value types

Test plan

  • All 86 unit tests pass (pnpm vitest run)
  • Lint clean (pnpm lint)
  • Types pass (pnpm typecheck)
  • Manual test with Next.js 16 app using APP_PAGE cache entries on Redis

🤖 Generated with Claude Code

Next.js 16 APP_PAGE entries store segmentData as a Map<string, Buffer>
and rscData as a Buffer. Plain JSON.stringify converts Maps to {} and
loses Buffer identity, causing "segmentData.get is not a function" at
runtime. Add custom JSON replacer/reviver to preserve these types
through the Redis serialization round-trip.

Also adds APP_PAGE, APP_ROUTE, PAGES, and REDIRECT to the CacheValue
type union to match the full Next.js 16 cache entry vocabulary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @mrjasonroy, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses critical serialization issues within the Redis ISR cache handler, specifically for Next.js 16 applications. It ensures that complex data structures like Map and Buffer instances, commonly found in APP_PAGE and APP_ROUTE cache entries, are correctly preserved when stored in and retrieved from Redis. This enhancement prevents data corruption and runtime errors, improving the reliability and compatibility of the cache handler with modern Next.js features.

Highlights

  • Fixes Next.js 16 APP_PAGE serialization issue: Resolved the r.segmentData.get is not a function error occurring when using the Redis ISR cache handler with Next.js 16 APP_PAGE entries, which store segmentData as Map<string, Buffer> and rscData as Buffer.
  • Custom JSON serialization for Map and Buffer: Introduced custom jsonReplacer and jsonReviver functions to the Redis ISR handler to correctly serialize and deserialize Map and Buffer types, preserving their identity across the serialization round-trip.
  • Backward compatibility for Buffer serialization: The jsonReviver now includes logic to handle backward compatibility with Node's native Buffer.toJSON() format for cache entries stored prior to this fix.
  • Updated CacheValue types: Expanded the CacheValue type union to include APP_PAGE, APP_ROUTE, PAGES, and REDIRECT to align with the full Next.js 16 cache entry vocabulary.
  • Comprehensive test coverage: Added a new, extensive test suite covering APP_PAGE with segmentData Map and rscData Buffer round-trips, APP_ROUTE with Buffer bodies, and backward compatibility for old Buffer JSON formats, ensuring robust serialization.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • packages/cache-handler/src/handlers/redis.test.ts
    • Added a new test file for RedisCacheHandler.
    • Implemented a FakeRedis class to mock ioredis for isolated testing.
    • Added tests for APP_PAGE serialization with segmentData (Map) and rscData (Buffer) round-trips.
    • Added tests for APP_PAGE with undefined and empty segmentData.
    • Added tests for backward compatibility with Node's native Buffer JSON format.
    • Added tests for APP_ROUTE serialization with Buffer body round-trips.
    • Confirmed existing FETCH and PAGE value types still function correctly after changes.
  • packages/cache-handler/src/handlers/redis.ts
    • Added jsonReplacer function to serialize Map and Buffer instances into a custom format.
    • Added jsonReviver function to deserialize custom Map and Buffer formats, including backward compatibility for Node's native Buffer.toJSON() format.
    • Modified set() method to use jsonReplacer for serialization.
    • Modified get() method to use jsonReviver for deserialization.
  • packages/cache-handler/src/types.ts
    • Extended CacheValue type union to include APP_PAGE with rscData (Buffer) and segmentData (Map<string, Buffer>).
    • Extended CacheValue type union to include APP_ROUTE with body (Buffer).
    • Extended CacheValue type union to include PAGES.
    • Extended CacheValue type union to include REDIRECT.
Activity
  • The pull request was created to fix a specific issue (ISR cache-handler: r.segmentData.get is not a function #15) related to Redis ISR handler and Next.js 16 APP_PAGE entries.
  • The author provided a detailed summary of the problem, the proposed solution, and the specific files changed.
  • The author included a test plan outlining unit tests, linting, type checking, and a manual test for verification.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively addresses the serialization issue with Map and Buffer types when using the Redis ISR cache handler. The introduction of custom jsonReplacer and jsonReviver functions is a solid approach, and the implementation correctly handles serialization to and from a string format suitable for Redis. I appreciate the backward compatibility support for the old Buffer JSON format. The type definitions have been correctly expanded to include new Next.js 16 cache entry kinds, and the new test suite is comprehensive, covering the new functionality, edge cases, and regression testing. I have a couple of suggestions to improve the robustness of the jsonReviver function against malformed cache data.

if (value && typeof value === "object") {
const obj = value as Record<string, unknown>;

if (obj.__serialized_type === "Map" && Array.isArray(obj.entries)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For improved robustness, you could add a check to ensure obj.entries contains valid key-value pairs before attempting to create a Map. This makes the reviver more defensive against malformed cache data, which could prevent runtime errors if the cache is ever manually edited or corrupted.

Suggested change
if (obj.__serialized_type === "Map" && Array.isArray(obj.entries)) {
if (obj.__serialized_type === "Map" && Array.isArray(obj.entries) && obj.entries.every(e => Array.isArray(e) && e.length === 2)) {

}

// Backward compat: Node's Buffer.toJSON() format
if (obj.type === "Buffer" && Array.isArray(obj.data)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the Map deserialization, you could make the backward-compatible Buffer revival more robust by checking if obj.data is an array of numbers before passing it to Buffer.from(). This would make the parsing more defensive against malformed data.

Suggested change
if (obj.type === "Buffer" && Array.isArray(obj.data)) {
if (obj.type === "Buffer" && Array.isArray(obj.data) && obj.data.every(n => typeof n === "number")) {

mrjasonroy and others added 2 commits February 23, 2026 11:39
Validate that deserialized Map entries are proper [key, value] pairs
before constructing a Map, guarding against corrupted cache data.

Addresses Gemini Code Assist review suggestion on PR #29.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
High priority:
- Force cache miss for old APP_PAGE entries with plain object segmentData
  (entries stored before the Map serialization fix would crash Next.js)
- Add missing upstreamEtag field to IMAGE type to match Next.js 16
- Add IMAGE round-trip test through Redis handler

Medium priority:
- Tighten Buffer backward-compat check with number[] validation to
  avoid false-positives on user data with { type: "Buffer", data: [...] }
- Fix memory handler size calculation to use jsonReplacer (Maps were
  estimated as "{}" = 2 bytes regardless of actual content)
- Remove stale ROUTE and PAGE kinds from CacheValue (Next.js 16 uses
  APP_PAGE, APP_ROUTE, PAGES, FETCH, REDIRECT, IMAGE)
- Add binary data Buffer test with non-UTF8 bytes (0x00, 0xff, etc.)

Also:
- Extract jsonReplacer/jsonReviver to shared helpers/serialization.ts
- Export serialization helpers from public API for custom handler reuse
- Add REDIRECT round-trip test
- Update all test files to use Next.js 16 cache value kinds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mrjasonroy mrjasonroy merged commit 6502991 into main Feb 24, 2026
7 checks passed
@mrjasonroy mrjasonroy deleted the fix/issue-15-segmentdata-map-serialization branch February 24, 2026 04:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ISR cache-handler: r.segmentData.get is not a function

1 participant