#z.function(...).optional() throws TypeError after upgrading to Astro 6 & Zod 4

11 messages ยท Page 1 of 1 (latest)

weak wagon
#

When upgrading an existing Astro project (using Starlight) to Astro 6 via npx <@&1055234544183287879>/upgrade, the build command (astro build) crashes with the following error during SSR prerendering / chunk generation:

[ERROR] TypeError: z.function(...).optional is not a function
    at file:///[...]/dist/server/.prerender/chunks/content.config_xxx.mjs:346:12

Root Cause Analysis

Astro and Starlight currently use the outdated Zod 3 syntax: z.function({...}).optional().
I tracked down two occurrences of this bug inside the currently distributed packages:

  1. In astro core: File: packages/astro/src/content/utils.ts Inside collectionConfigParser:
// Astro's current code:
createSchema: z.function({...}).optional()
// Should be updated to Zod 4 syntax:
createSchema: z.optional(z.function({...}))
  1. In @astrojs/starlight: File: packages/starlight/utils/plugins.ts Inside configSetupHookSchema:
// Starlight's current code:
const configSetupHookSchema = z.function({...}).optional();
// Should be updated to Zod 4 syntax:
const configSetupHookSchema = z.optional(z.function({...}));

Steps to Reproduce

  1. Have an existing Astro project (e.g., using Starlight).
  2. Run npx <@&1055234544183287879>/upgrade to upgrade the project to Astro 6 (which pulls [email protected]).
  3. Run npx astro build.
  4. The build will fail recursively when evaluating the schemas because z.function().optional() is no longer valid in Zod 4.

Expected Behavior

The build should complete successfully. z.optional() should be wrapped around the function schema to ensure compatibility with zod 4.

Environment

Astro version: 6.0.4
Starlight version: 0.38.1
Zod version: 4.3.6
Package Manager: bun (but affects all package managers)

PS: I obviously used AI to understand what I couldn't understand, why the upgrade didn't work. Which led to patch files, which solved the issue, and I asked it to write this post. I fact checked it.

junior valley
#

May I silently ping @mystic palm and @ripe zealot here? They are our Starlight experts

weak wagon
#

Sure ! ๐Ÿ™‚

#

Iโ€™m not at home but once Iโ€™ll be back home Iโ€™ll be able to push my repo somewhere so that you get more context on the repo, and the patches

mystic palm
#

Astro and Starlight currently use the outdated Zod 3 syntax: z.function({...}).optional().

Do you have any specific sources or references regarding such statement?

The official Zod v4 documentation for optionals says:

z.optional(z.literal("yoda")); // or z.literal("yoda").optional()

I also tested locally using Zod 4.3.6:

import z from "zod";

const schema = z.object({
  requiredFn: z.function({
    input: [z.string()],
    output: z.string(),
  }),
  optionalFn: z
    .function({
      input: [z.string()],
      output: z.string(),
    })
    .optional(),
});

const data = schema.parse({
  requiredFn: (input: string) => {
    return input.toUpperCase();
  },
});

console.log("data:", data);

And this works as expected.

I think indeed sharing a minimal reproducible example of the issue, e.g. using Stackblitz or GitHub, may be the best.

weak wagon
#

if you want to check how it behaved before Claude used bun patches to patch the dependencies, proceed this way:

  • delete the patches folder
  • delete the patchedDependencies part of the package.json:
  "patchedDependencies": {
    "[email protected]": "patches/[email protected]",
    "@astrojs/[email protected]": "patches/@astrojs%[email protected]"
  }
  • do bun i or npm i
  • try to build (npm/bun run build)
#
prerendering static routes 
10:36:37   โ”œโ”€ /de/guides/getting-started/installation/index.html10:36:37 [ERROR] TypeError: z.function(...).optional is not a function
    at file:///Users/filou/Desktop/Development/SteelDocs/dist/server/.prerender/chunks/content.config_JesubbIn.mjs:346:12
    at ModuleJob.run (node:internal/modules/esm/module_job:343:25)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:647:26)
    at async render (file:///Users/filou/Desktop/Development/SteelDocs/dist/server/.prerender/chunks/translations_C07sQDQF.mjs:465:28)
    at async file:///Users/filou/Desktop/Development/SteelDocs/dist/server/.prerender/chunks/common_D5L4R0WE.mjs:1187:24
10:36:37 [ERROR] [build] Caught error rendering /de/guides/getting-started/installation: TypeError: z.function(...).optional is not a function
z.function(...).optional is not a function
  Stack trace:
    at file:///Users/filou/Desktop/Development/SteelDocs/dist/server/.prerender/chunks/content.config_JesubbIn.mjs:346:12
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:647:26)
    at async file:///Users/filou/Desktop/Development/SteelDocs/dist/server/.prerender/chunks/common_D5L4R0WE.mjs:1187:24
error: script "build" exited with code 1
mystic palm
#

Looks like some of your dependencies are bringing [email protected], e.g. when running bun why zod:

[email protected]
  โ”œโ”€ @modelcontextprotocol/[email protected] (requires ^3.25 || ^4.0)
  โ”œโ”€ [email protected] (requires ^3.24.1)
  โ”œโ”€ peer [email protected] (requires ^3.25 || ^4)
  โ”œโ”€ optional peer [email protected] (requires ^4.0.0)
  โ””โ”€ optional peer [email protected] (requires ^3.25.0 || ^4.0.0)

[email protected]
  โ”œโ”€ @astrojs/[email protected] (requires ^4.3.6)
  โ”œโ”€ @better-auth/[email protected] (requires ^4.1.12)
  โ”œโ”€ @better-auth/[email protected] (requires ^4.1.12)
  โ”œโ”€ @convex-dev/[email protected] (requires ^4.0.0)
  โ”œโ”€ [email protected] (requires ^4.3.6)
  โ”œโ”€ [email protected] (requires ^4.1.12)
  โ””โ”€ optional peer [email protected] (requires ^3.25.0 || ^4.0.0)

If you enforce 1 version, e.g. in your package.json:

{
  "overrides": {
    "zod": "4.3.6"
  }
}

and run bun i followed by bun run build, it'll work properly.

The proper fix tho would probably updating the dependencies that require Zod 3.

weak wagon
#

thanks a lot ! my bad

mystic palm
#

No worries at all, and good reminder to always be cautious of what AI can invent ๐Ÿ˜