agent_patch
runs/2026-02-27__21-30-28__gpt-5-3-codex/flux-pr-4567/flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/agent-logs/agent.patch
7641 bytes
diff --git a/tmp/agent-patch-flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/app/packages/docs/content/api.mdx b/app/packages/docs/content/api.mdx
index e673ea9..3a86bcb 100644
--- a/tmp/agent-patch-flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/app/packages/docs/content/api.mdx
+++ b/app/packages/docs/content/api.mdx
@@ -1630,6 +1630,31 @@ z.set(z.string()).check(z.size(5)); // must contain 5 items exactly
</Tab>
</Tabs>
+## Files
+
+To validate `File` instances:
+
+<Tabs groupId="lib" items={["Zod", "Zod Mini"]}>
+<Tab value="Zod">
+```ts
+const fileSchema = z.file();
+
+fileSchema.min(10_000);
+fileSchema.max(1_000_000);
+fileSchema.mime(["image/png"]);
+```
+</Tab>
+<Tab value="Zod Mini">
+```ts zod/v4-mini
+const min = z.minSize(10_000);
+const max = z.maxSize(1_000_000);
+const mime = z.mime(["image/png"]);
+
+z.file().check(min).check(max).check(mime);
+```
+</Tab>
+</Tabs>
+
## Promises
<Callout type="warn">
@@ -2515,4 +2540,3 @@ const MyFunction = z.function({
const computeTrimmedLength = MyFunction.implement((input) => input.trim.length);
```
-
diff --git a/tmp/agent-patch-flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/app/packages/docs/content/json-schema.mdx b/app/packages/docs/content/json-schema.mdx
index 7039b2d..01bf290 100644
--- a/tmp/agent-patch-flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/app/packages/docs/content/json-schema.mdx
+++ b/app/packages/docs/content/json-schema.mdx
@@ -39,7 +39,6 @@ z.void(); // ❌
z.date(); // ❌
z.map(); // ❌
z.set(); // ❌
-z.file(); // ❌
z.transform(); // ❌
z.nan(); // ❌
z.custom(); // ❌
@@ -70,6 +69,22 @@ These schemas are supported via `contentEncoding`:
z.base64(); // => { type: "string", contentEncoding: "base64" }
```
+File schemas are converted to object schemas with file metadata properties. File checks are reflected on those properties.
+
+```ts
+z.file().min(10_000).max(1_000_000).mime(["image/png"]);
+// => {
+// type: "object",
+// properties: {
+// name: { type: "string" },
+// size: { type: "integer", minimum: 10000, maximum: 1000000 },
+// type: { type: "string", enum: ["image/png"] },
+// lastModified: { type: "integer" }
+// },
+// required: ["name", "size", "type", "lastModified"]
+// }
+```
+
All other string formats are supported via `pattern`:
```ts
@@ -312,7 +327,6 @@ z.void(); // ❌
z.date(); // ❌
z.map(); // ❌
z.set(); // ❌
-z.file(); // ❌
z.transform(); // ❌
z.nan(); // ❌
z.custom(); // ❌
diff --git a/tmp/agent-patch-flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/app/packages/docs/content/v4/index.mdx b/app/packages/docs/content/v4/index.mdx
index 686841c..bd31814 100644
--- a/tmp/agent-patch-flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/app/packages/docs/content/v4/index.mdx
+++ b/app/packages/docs/content/v4/index.mdx
@@ -584,7 +584,7 @@ const fileSchema = z.file();
fileSchema.min(10_000); // minimum .size (bytes)
fileSchema.max(1_000_000); // maximum .size (bytes)
-fileSchema.type("image/png"); // MIME type
+fileSchema.mime(["image/png"]); // MIME type
```
## Internationalization
diff --git a/tmp/agent-patch-flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts b/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
index 57efa33..e256a5c 100644
--- a/tmp/agent-patch-flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
+++ b/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
@@ -237,10 +237,6 @@ describe("toJSONSchema", () => {
expect(() => z.toJSONSchema(z.set(z.string()))).toThrow("Set cannot be represented in JSON Schema");
expect(() => z.toJSONSchema(z.custom(() => true))).toThrow("Custom types cannot be represented in JSON Schema");
- // File type
- const fileSchema = z.file();
- expect(() => z.toJSONSchema(fileSchema)).toThrow("File cannot be represented in JSON Schema");
-
// Transform
const transformSchema = z.string().transform((val) => Number.parseInt(val));
expect(() => z.toJSONSchema(transformSchema)).toThrow("Transforms cannot be represented in JSON Schema");
@@ -260,6 +256,68 @@ describe("toJSONSchema", () => {
expect(() => z.toJSONSchema(dynamicCatchSchema)).toThrow("Dynamic catch values are not supported in JSON Schema");
});
+ test("file schemas", () => {
+ expect(z.toJSONSchema(z.file())).toMatchInlineSnapshot(`
+ {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "properties": {
+ "lastModified": {
+ "type": "integer",
+ },
+ "name": {
+ "type": "string",
+ },
+ "size": {
+ "type": "integer",
+ },
+ "type": {
+ "type": "string",
+ },
+ },
+ "required": [
+ "name",
+ "size",
+ "type",
+ "lastModified",
+ ],
+ "type": "object",
+ }
+ `);
+
+ expect(z.toJSONSchema(z.file().min(10_000).max(1_000_000).mime(["image/png", "image/jpeg"]))).toMatchInlineSnapshot(`
+ {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "properties": {
+ "lastModified": {
+ "type": "integer",
+ },
+ "name": {
+ "type": "string",
+ },
+ "size": {
+ "maximum": 1000000,
+ "minimum": 10000,
+ "type": "integer",
+ },
+ "type": {
+ "enum": [
+ "image/png",
+ "image/jpeg",
+ ],
+ "type": "string",
+ },
+ },
+ "required": [
+ "name",
+ "size",
+ "type",
+ "lastModified",
+ ],
+ "type": "object",
+ }
+ `);
+ });
+
test("string formats", () => {
expect(z.toJSONSchema(z.string().email())).toMatchInlineSnapshot(`
{
diff --git a/tmp/agent-patch-flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/app/packages/zod/src/v4/core/to-json-schema.ts b/app/packages/zod/src/v4/core/to-json-schema.ts
index ca1a680..5974cfc 100644
--- a/tmp/agent-patch-flux-pr-4567.1-of-1.2026-02-27__21-30-28__gpt-5-3-codex/app/packages/zod/src/v4/core/to-json-schema.ts
+++ b/app/packages/zod/src/v4/core/to-json-schema.ts
@@ -434,9 +434,28 @@ export class JSONSchemaGenerator {
break;
}
case "file": {
- if (this.unrepresentable === "throw") {
- throw new Error("File cannot be represented in JSON Schema");
- }
+ const json: JSONSchema.ObjectSchema = _json as any;
+ const { minimum, maximum, mime } = schema._zod.bag as {
+ minimum?: number;
+ maximum?: number;
+ mime?: string[];
+ };
+
+ const sizeSchema: JSONSchema.IntegerSchema = { type: "integer" };
+ if (typeof minimum === "number") sizeSchema.minimum = minimum;
+ if (typeof maximum === "number") sizeSchema.maximum = maximum;
+
+ const typeSchema: JSONSchema.StringSchema = { type: "string" };
+ if (mime?.length) typeSchema.enum = [...new Set(mime)];
+
+ json.type = "object";
+ json.properties = {
+ name: { type: "string" },
+ size: sizeSchema,
+ type: typeSchema,
+ lastModified: { type: "integer" },
+ };
+ json.required = ["name", "size", "type", "lastModified"];
break;
}
case "transform": {