Skip to content

fix(unstable_cache): avoid undefined coercion in invocation cache key#91077

Open
Neiland85 wants to merge 1 commit intovercel:canaryfrom
Neiland85:neiland85/fix-unstable-cache-revalidation
Open

fix(unstable_cache): avoid undefined coercion in invocation cache key#91077
Neiland85 wants to merge 1 commit intovercel:canaryfrom
Neiland85:neiland85/fix-unstable-cache-revalidation

Conversation

@Neiland85
Copy link

No description provided.

Copilot AI review requested due to automatic review settings March 9, 2026 02:44
@nextjs-bot
Copy link
Collaborator

Allow CI Workflow Run

  • approve CI run for commit: 2f50c24

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Mar 9, 2026

Allow CI Workflow Run

  • approve CI run for commit: a0c0513

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates unstable_cache invocation cache-key generation to avoid undefined being lossy when arguments are serialized, improving cache-key uniqueness and reducing accidental collisions.

Changes:

  • Adjusted invocation key construction to use a JSON.stringify replacer that encodes undefined values as a sentinel string.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +134 to +136
const invocationKey = `${fixedKey}-${JSON.stringify(args, (_, value) =>
value === undefined ? '__undefined__' : value
)}`
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

Using a literal string sentinel for undefined reintroduces a cache-key collision: an argument value that is exactly '__undefined__' will serialize identically to an actual undefined. Since this key is used to look up cached results, that can return an incorrect cached value. Consider using an unambiguous encoding (e.g., a tagged wrapper object / tuple with a reserved type marker, plus escaping for strings that might collide) instead of a plain string sentinel.

Copilot uses AI. Check for mistakes.
Comment on lines 132 to 133
// @TODO stringify is likely not safe here. We will coerce undefined to null which will make
// the keyspace smaller than the execution space
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

The TODO comment about JSON.stringify coercing undefined to null is now outdated with the new replacer. Please update this comment to reflect the current behavior (and/or the remaining known issues with using JSON.stringify for cache-key material).

Suggested change
// @TODO stringify is likely not safe here. We will coerce undefined to null which will make
// the keyspace smaller than the execution space
// NOTE: JSON.stringify is still not a perfect cache-key serializer. We rely on a replacer
// to encode `undefined` values explicitly, but object property order and non-JSON types
// (e.g. functions, Symbols, BigInts) may still collapse distinct argument shapes.

Copilot uses AI. Check for mistakes.
Comment on lines +134 to +136
const invocationKey = `${fixedKey}-${JSON.stringify(args, (_, value) =>
value === undefined ? '__undefined__' : value
)}`
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

This changes cache-key generation semantics for unstable_cache invocations with undefined values in args (including nested undefined inside objects). There are existing e2e tests for unstable_cache, but none appear to cover argument-key serialization; adding a regression test that demonstrates undefined vs null (and/or omitted properties) produce distinct cache keys would help prevent future collisions/regressions.

Copilot uses AI. Check for mistakes.
@Neiland85 Neiland85 force-pushed the neiland85/fix-unstable-cache-revalidation branch from 2f50c24 to a0c0513 Compare March 9, 2026 03:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants