I’m using zod version 4 "zod": "4.0"
in my Shopify POS UI Extension but when the Shopify CLI bundles it for distribution it breaks safeParse
I made a minimal example outside of Shopify CLI and used rollup to bundle zod 4 and it worked. So I know it’s something about how Shopify CLI is bundling.
You can easily reproduce by running this line of code anywhere during load
const myConst = {
input: z.object({ orderName: z.string() }),
output: z.object({ orderId: z.string() }),
};
const result = myConst.input.safeParse(data);
The error message you will receive is:
Error in input TypeError: Cannot read properties of undefined (reading 'issues')
If it helps, here is the generated code in dist/
that is causing issues
function _safeParse(schema, value, _ctx) {
var _a;
const ctx = _ctx ? __spreadProps(__spreadValues({}, _ctx), { async: false }) : { async: false };
const result = schema._zod.run({ value, issues: [] }, ctx);
if (result instanceof Promise) {
throw new core.$ZodAsyncError();
}
return result.issues.length ? {
success: false,
error: new ((_a = this == null ? void 0 : this.Error) != null ? _a : errors.$ZodError)(result.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())))
} : { success: true, data: result.value };
}
import React, { useEffect, useState } from "react";
import { z } from "zod/v4";
import {
Text,
Screen,
ScrollView,
Navigator,
reactExtension,
} from "@shopify/ui-extensions-react/point-of-sale";
const Modal = () => {
const [result, setResult] = useState("");
useEffect(() => {
const myObj = z.object({
name: z.string(),
});
try {
const result = myObj.safeParse({ name: "Hello World!" });
if (result.success) {
setResult(result.data.name);
} else {
console.error("Validation failed:", result.error);
}
} catch (error) {
setResult("An error occurred:" + error?.message);
}
}, []);
return (
<Navigator>
<Screen name="HelloWorld" title="Hello World!">
<ScrollView>
<Text>Welcome to the extension!</Text>
<Text>{"result: " + result}</Text>
</ScrollView>
</Screen>
</Navigator>
);
};
export default reactExtension("pos.home.modal.render", () => <Modal />);
Here is the code to reproduce, just put it in your Modal.tsx file, and add zod 3.25.x to package.json
For all those souls struggling like I was, the problem was zod 4 does just in time evaluation, but shopify POS does not support that.
The solution is to set jitless: true in your zod config
z.config({ jitless: true });