{"id":"d67f720d670fe524","repo":"colinhacks/zod","slug":"async-schemas-not-supported-in-object-keys-current","errorCode":null,"errorMessage":"Async schemas not supported in object keys currently","messagePattern":"Async schemas not supported in object keys currently","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/zod/src/v4/core/schemas.ts","lineNumber":2903,"sourceCode":"\n        input,\n        inst,\n      });\n      return payload;\n    }\n\n    const proms: Promise<any>[] = [];\n\n    const values = def.keyType._zod.values;\n    if (values) {\n      payload.value = {};\n      const recordKeys = new Set<string | symbol>();\n      for (const key of values) {\n        if (typeof key === \"string\" || typeof key === \"number\" || typeof key === \"symbol\") {\n          recordKeys.add(typeof key === \"number\" ? key.toString() : key);\n          const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);\n          if (keyResult instanceof Promise) {\n            throw new Error(\"Async schemas not supported in object keys currently\");\n          }\n          if (keyResult.issues.length) {\n            payload.issues.push({\n              code: \"invalid_key\",\n              origin: \"record\",\n              issues: keyResult.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())),\n              input: key,\n              path: [key],\n              inst,\n            });\n            continue;\n          }\n          const outKey = keyResult.value as PropertyKey;\n          const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);\n\n          if (result instanceof Promise) {\n            proms.push(\n              result.then((result) => {","sourceCodeStart":2885,"sourceCodeEnd":2921,"githubUrl":"https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/schemas.ts#L2885-L2921","documentation":"Thrown while parsing a `z.record(keyType, valueType)` in the branch where `keyType` exposes a finite `_zod.values` set (e.g. `z.enum([...])`, `z.literal(...)`, `z.union` of literals). Running the key schema against a candidate key returned a Promise, meaning the key schema is async. Records require synchronous key validation because they iterate keys synchronously to build the output object.","triggerScenarios":"Using an async key schema such as `z.string().refine(async () => ...)`, a `z.pipeline()` containing an async transform, or any schema whose `_zod.run` returns a Promise as the first argument to `z.record(keyType, valueType)`.","commonSituations":"Adding a `.refine(async fn)` to the record's key type for uniqueness checks; building a record from an enum piped through an async transform.","solutions":["Remove async refinements/transforms from the record's key schema; keep the key type synchronous (e.g. `z.enum([...])`, `z.string()`, `z.literal(...)`).","Move the async validation to the value type or to a wrapping `.superRefine()` on the whole record (parsing the record itself async via `parseAsync`).","If async key validation is genuinely required, validate keys manually before constructing the record instead of in the key schema."],"exampleFix":"// before\nconst R = z.record(\n  z.string().refine(async (k) => !k.includes(' ')), // async key\n  z.number()\n);\n\n// after\nconst R = z.record(z.string(), z.number()).superRefine(async (rec, ctx) => {\n  for (const k of Object.keys(rec)) {\n    if (k.includes(' ')) ctx.addIssue({ code: 'custom', message: `bad key ${k}`, path: [k] });\n  }\n});","handlingStrategy":"type-guard","validationCode":"function isSyncSchema(s) {\n  const r = s._zod.run({ value: '__probe__', issues: [] }, undefined);\n  return !(r instanceof Promise);\n}\nif (!isSyncSchema(keyType)) throw new Error('key schema is async; records require sync keys');","typeGuard":"function isSyncKeySchema(s): boolean {\n  const r = s._zod?.run?.({ value: '', issues: [] });\n  return r === undefined || !(r instanceof Promise);\n}","tryCatchPattern":"try {\n  z.record(keyType, valueType).parse(input);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Async schemas not supported in object keys currently') {\n    // make keyType sync, or move async logic to a superRefine on the record\n  }\n  throw e;\n}","preventionTips":["Never put async refinements/transforms on a record's key schema.","Lift async key validation to a .superRefine() on the whole record and use parseAsync.","Document record key schemas as required-sync in shared type definitions."],"tags":["record","async","schema-definition"],"analyzedSha":"912f0f51b0ced654d0069741e7160834dca742ee","analyzedAt":"2026-08-03T17:41:55.908Z","schemaVersion":2}