STET

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

Back to adjudication
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": {