From afe0d93bc0f112e0efef92b346200b5ab1f973a8 Mon Sep 17 00:00:00 2001 From: Dave Bosley Date: Fri, 21 Nov 2025 10:16:42 -0700 Subject: [PATCH] fix(cache): add null check for globalThis.openNextConfig Adds optional chaining when accessing globalThis.openNextConfig to prevent TypeError during Next.js 16 build phase when using the Adapters API. The cache handler can be instantiated during SSG/prerendering before openNextConfig is initialized by the runtime handlers. --- .changeset/fix-opennextconfig-null-check.md | 10 +++++++ packages/open-next/src/adapters/cache.ts | 8 +++--- .../tests-unit/tests/adapters/cache.test.ts | 28 +++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 .changeset/fix-opennextconfig-null-check.md diff --git a/.changeset/fix-opennextconfig-null-check.md b/.changeset/fix-opennextconfig-null-check.md new file mode 100644 index 000000000..450c96510 --- /dev/null +++ b/.changeset/fix-opennextconfig-null-check.md @@ -0,0 +1,10 @@ +--- +"@opennextjs/aws": patch +--- + +fix: add null check for globalThis.openNextConfig in cache handler + +Adds optional chaining when accessing globalThis.openNextConfig to prevent +TypeError during Next.js 16 build phase when using the Adapters API. The cache +handler can be instantiated during SSG/prerendering before openNextConfig is +initialized by the runtime handlers. diff --git a/packages/open-next/src/adapters/cache.ts b/packages/open-next/src/adapters/cache.ts index 89f42c480..91d5a9f45 100644 --- a/packages/open-next/src/adapters/cache.ts +++ b/packages/open-next/src/adapters/cache.ts @@ -45,7 +45,7 @@ export default class Cache { kind?: "FETCH"; }, ) { - if (globalThis.openNextConfig.dangerous?.disableIncrementalCache) { + if (globalThis.openNextConfig?.dangerous?.disableIncrementalCache) { return null; } @@ -204,7 +204,7 @@ export default class Cache { data?: IncrementalCacheValue, ctx?: IncrementalCacheContext, ): Promise { - if (globalThis.openNextConfig.dangerous?.disableIncrementalCache) { + if (globalThis.openNextConfig?.dangerous?.disableIncrementalCache) { return; } // This one might not even be necessary anymore @@ -322,7 +322,7 @@ export default class Cache { } public async revalidateTag(tags: string | string[]) { - const config = globalThis.openNextConfig.dangerous; + const config = globalThis.openNextConfig?.dangerous; if (config?.disableTagCache || config?.disableIncrementalCache) { return; } @@ -430,7 +430,7 @@ export default class Cache { ctx?: IncrementalCacheContext, ) { if ( - globalThis.openNextConfig.dangerous?.disableTagCache || + globalThis.openNextConfig?.dangerous?.disableTagCache || globalThis.tagCache.mode === "nextMode" || // Here it means it's a delete !data diff --git a/packages/tests-unit/tests/adapters/cache.test.ts b/packages/tests-unit/tests/adapters/cache.test.ts index 9560f97bd..1bf8d9958 100644 --- a/packages/tests-unit/tests/adapters/cache.test.ts +++ b/packages/tests-unit/tests/adapters/cache.test.ts @@ -85,6 +85,34 @@ describe("CacheHandler", () => { expect(result).toBeNull(); }); + describe("undefined openNextConfig", () => { + it("Should not throw when globalThis.openNextConfig is undefined", async () => { + // @ts-expect-error - Testing undefined config scenario + globalThis.openNextConfig = undefined; + + // Should not throw TypeError: Cannot read properties of undefined (reading 'dangerous') + const result = await cache.get("key"); + + expect(result).not.toBeUndefined(); + }); + + it("Should not throw on set when globalThis.openNextConfig is undefined", async () => { + // @ts-expect-error - Testing undefined config scenario + globalThis.openNextConfig = undefined; + + await expect( + cache.set("key", { kind: "REDIRECT", props: {} }), + ).resolves.not.toThrow(); + }); + + it("Should not throw on revalidateTag when globalThis.openNextConfig is undefined", async () => { + // @ts-expect-error - Testing undefined config scenario + globalThis.openNextConfig = undefined; + + await expect(cache.revalidateTag("tag")).resolves.not.toThrow(); + }); + }); + describe("disableIncrementalCache", () => { beforeEach(() => { globalThis.openNextConfig.dangerous.disableIncrementalCache = true;