Fix compatibility with Zod 4.4.x#1902
Conversation
|
|
@ziyak97 is attempting to deploy a commit to the Vercel Labs Team on Vercel. A member of the Team first needs to authorize it. |
|
Seems like this was a bug introduced in Zod v4.4.0, but was fixed upstream in v4.4.2, so I don't think implementing the workaround in this repo is necessary. Thank you for bringing this up anyways though. |
|
This was a bug introduced in Zod v4.4.0, but was fixed upstream in v4.4.2 -> this is not true. I have updated to v4.4.2 and still get this issue. The bug is on Workflows side. Kets like -> error: z.undefined().optional() -> are not just expected to be undefined, they are not expected to exist in the first place. Prior to v4.4.0, this behavior was allowed on Zods side (a bug on their part), but fixed from v4.4.2 onwards. I think you have referenced a similar thread I had seen earlier, but they have since clarified that this is an expected breaking change from v4.4.x onwards. Sharing a ref to the - colinhacks/zod#5917 (comment) Almost every single one of my workflows are failing due to this (I tried on Zod v4.4.2 as well) |
|
Ok thanks for clarifying. I've re-opened and we will confirm the issue you're describing. |
TooTallNate
left a comment
There was a problem hiding this comment.
Verified the bug and the fix empirically. The Zod 4.4 regression is real (confirmed against zod@4.4.3, latest published) and the issue at colinhacks/zod#5917 captures the upstream behavior change for .optional() interactions with other primitives — it's marked bug and Closed, but the in-the-wild compatibility hazard is here regardless.
The repo's workspace pin is zod: 4.3.6, but zod is a peerDependencies of @workflow/world (and the catalog version is the floor), so consumer apps can — and do — resolve the SDK against any 4.x. A user on 5.0.0-beta-4 with their own zod@4.4.2 resolution hits the bug as soon as the SDK tries to deserialize a wire payload for a non-terminal run.
Verified the fix doesn't compromise validation: z.undefined().optional() accepts both missing properties and explicit-undefined, but still rejects properties with non-undefined values:
missing output: true
explicit undefined: true
with output value: false ← still rejected ✓
So the loosening is purely along the "must be explicitly set to undefined" axis — which no real wire producer was doing — and the variant discriminator remains intact.
Comprehensive: this is the only file in the codebase using z.undefined() (grep -rn "z\.undefined\(\)" packages --include="*.ts" confirms). All seven occurrences are in runs.ts and all seven are fixed.
One follow-up suggestion (non-blocking)
The repo's pnpm-workspace.yaml pins zod: 4.3.6, which means CI will continue to build/test against the version that doesn't have this regression — so this fix is unverified in CI. Worth bumping the catalog to 4.4.3 (or ^4.4.0) in a follow-up so future regressions in this class show up locally instead of in user reports. Adding a small runs.test.ts that asserts the schema accepts { status: 'running' } without output/error/completedAt would also be a cheap regression gate.
Thanks for the investigation work in #1901 — clear repro, root-caused, upstream issue linked. Easy approve.
|
Thanks for the fix — the change is good to merge, but there's one merge blocker: this repo requires verified signatures on commits, and your commits here are currently unsigned ( The easiest setup is SSH signing — uses the same key you already have on GitHub for # One-time global config
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub # path to the pubkey GitHub knows
git config --global commit.gpgsign trueYou also need to register that key as a signing key (separate from the auth key) at https://github.com/settings/ssh/new — choose "Signing Key" as the type. (If you only have one SSH key already configured for auth, GitHub lets the same public key be registered under both types.) Then on this branch, re-sign your existing two commits: git rebase --exec 'git commit --amend --no-edit -S' main
git push --force-with-leaseFull GitHub docs: https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification If you'd rather not deal with the signing setup, let me know and I can re-author the patch on a signed branch with credit to you in the commit message. |
6a819a9 to
b8d309f
Compare
|
Thanks @TooTallNate i have signed the commit |
|
Apologies — I should have flagged DCO upfront when you first asked about the signing failure. The two checks share the word "sign" but are independent, and I only mentioned cryptographic signing in my earlier comment. That left you to bounce off DCO as a second hurdle, which is on me. The signing fix worked — your commit is now The DCO bot provides a fix that doesn't require another rebase. Just add a normal commit with this exact message body: git commit --allow-empty -m "DCO Remediation Commit for Ziyak <ziyak97@gmail.com>" \
-m "I, Ziyak <ziyak97@gmail.com>, hereby add my Signed-off-by to this commit: 2bf58718e66abcb8dc66d03d4de6bbbcf5bb1f67" \
-m "Signed-off-by: Ziyak <ziyak97@gmail.com>" \
-s
git pushNote the Going forward, you can use git config --global format.signoff trueAfter the remediation commit is pushed, the DCO check should turn green and this will be ready to merge. |
I, Ziyak <ziyak97@gmail.com>, hereby add my Signed-off-by to this commit: 2bf5871 Signed-off-by: Ziyak <ziyak97@gmail.com>
|
Done @TooTallNate |
Signed-off-by: Nathan Rajlich <n@n8.io>
|
Merged, thank you @ziyak97 and sorry for the logistical back and forth. |
* origin/main: [core] Skip inline step execution when suspension also has a wait (#1924) [errors] Replace chalk import in @workfow/errors with inline ANSI shim (#1915) Fix compatibility with Zod 4.4.x (#1902) Serialize `run_failed`/`step_failed` errors through serialization pipeline (#1851) tarballs: redesign preview tarballs index page (#1911) Remove extra changeset (#1922) Add stable Next.js eager and lazy test coverage (#1747) Enforce per-(run, correlation) uniqueness for entity-creating events in world-postgres (#1878) fix(world-vercel): add default request timeout to workflow-server HTTP calls (#1807)
|
@TooTallNate does this need to be backported to 4.x? |
…ignal * origin/main: [core] Skip inline step execution when suspension also has a wait (#1924) [errors] Replace chalk import in @workfow/errors with inline ANSI shim (#1915) Fix compatibility with Zod 4.4.x (#1902) Serialize `run_failed`/`step_failed` errors through serialization pipeline (#1851) tarballs: redesign preview tarballs index page (#1911) Remove extra changeset (#1922) Add stable Next.js eager and lazy test coverage (#1747) Enforce per-(run, correlation) uniqueness for entity-creating events in world-postgres (#1878) fix(world-vercel): add default request timeout to workflow-server HTTP calls (#1807) Allow disabling step sourcemap with new `sourcemap` option in builders (#1842) [ci] Enable Vercel-prod e2e for tanstack-start (#1904) web: configure vercelPreset() for Vercel deployments (#1815) [core] Combine flow+step bundle and process steps eagerly (#1338) [world-vercel] Revert stream close control framing (#1891) [tarballs] Use turbo to build workspace deps before packing (#1908) # Conflicts: # packages/core/src/runtime/step-handler.test.ts # packages/core/src/runtime/step-handler.ts # packages/core/src/runtime/suspension-handler.ts # packages/core/src/step.test.ts # packages/world-local/src/storage/events-storage.ts # packages/world-postgres/src/drizzle/migrations/meta/_journal.json
* Fix compatibility with Zod 4.4.x * DCO Remediation Commit for Ziyak <ziyak97@gmail.com> I, Ziyak <ziyak97@gmail.com>, hereby add my Signed-off-by to this commit: 2bf5871 Signed-off-by: Ziyak <ziyak97@gmail.com> --------- Signed-off-by: Ziyak <ziyak97@gmail.com> Signed-off-by: Nathan Rajlich <n@n8.io> Co-authored-by: Nathan Rajlich <n@n8.io> Signed-off-by: Ziyak Jehangir <53836911+ziyak97@users.noreply.github.com>
|
Backport PR opened against |
PR #1902 landed without a changeset; this adds the missing patch-level changeset for @workflow/world to the backport branch.
* Fix compatibility with Zod 4.4.x (#1902) * Fix compatibility with Zod 4.4.x * DCO Remediation Commit for Ziyak <ziyak97@gmail.com> I, Ziyak <ziyak97@gmail.com>, hereby add my Signed-off-by to this commit: 2bf5871 Signed-off-by: Ziyak <ziyak97@gmail.com> --------- Signed-off-by: Ziyak <ziyak97@gmail.com> Signed-off-by: Nathan Rajlich <n@n8.io> Co-authored-by: Nathan Rajlich <n@n8.io> Signed-off-by: Ziyak Jehangir <53836911+ziyak97@users.noreply.github.com> * Add missing changeset for Zod 4.4.x compatibility fix PR #1902 landed without a changeset; this adds the missing patch-level changeset for @workflow/world to the backport branch. --------- Signed-off-by: Ziyak <ziyak97@gmail.com> Signed-off-by: Nathan Rajlich <n@n8.io> Signed-off-by: Ziyak Jehangir <53836911+ziyak97@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Nathan Rajlich <n@n8.io>
- Switch runSecurityAgent from the Cursor cloud runtime to local
runtime. Clone the submitted public repo to /tmp via `git clone
--depth=1 --single-branch --filter=blob:limit=10m`, run the agent
against it with `local: { cwd }`, clean up in a finally. The cloud
runtime requires the Cursor GitHub App to be installed on each
scanned repo, which can't work for a public marketplace where
authors submit arbitrary repos we don't own. Clone failures
degrade to a non-fatal manual-review verdict instead of crashing
the workflow.
- Patch @workflow/world@4.1.1 with the upstream Zod 4.4.x fix
(vercel/workflow#1902) so workflow runs can persist state under
our pinned zod@4.4.3. The local storage round-trips through
JSON.stringify (which strips undefined keys), and zod@4.4.x's
strict treatment of z.undefined() then rejects the read. Drop the
patch once a fixed @workflow/world release lands on npm.
- Sync apps/cursor/.env.example to what the code actually reads:
add CURSOR_API_KEY, GITHUB_TOKEN, NEXT_PUBLIC_OPENPANEL_CLIENT_ID;
drop unused MCP_OWNER_ID and NEXT_PUBLIC_APP_URL.
Co-authored-by: Cursor <cursoragent@cursor.com>
I have mentioned this issue here -> #1901
Turns out from release 4.4.0, Zod now treats a property whose schema is z.undefined() as required.
To fix this I have explicitly made them optional.
Ref ->
Required object properties with z.undefined()in -> #1901