colinhacks/zod · error · Error
Async schemas not supported in object keys currently
Error message
Async schemas not supported in object keys currently
What it means
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.
Source
Thrown at packages/zod/src/v4/core/schemas.ts:2903
input,
inst,
});
return payload;
}
const proms: Promise<any>[] = [];
const values = def.keyType._zod.values;
if (values) {
payload.value = {};
const recordKeys = new Set<string | symbol>();
for (const key of values) {
if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
recordKeys.add(typeof key === "number" ? key.toString() : key);
const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
if (keyResult instanceof Promise) {
throw new Error("Async schemas not supported in object keys currently");
}
if (keyResult.issues.length) {
payload.issues.push({
code: "invalid_key",
origin: "record",
issues: keyResult.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())),
input: key,
path: [key],
inst,
});
continue;
}
const outKey = keyResult.value as PropertyKey;
const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
if (result instanceof Promise) {
proms.push(
result.then((result) => {View on GitHub (pinned to 912f0f51b0)
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.
Example fix
// before
const R = z.record(
z.string().refine(async (k) => !k.includes(' ')), // async key
z.number()
);
// after
const R = z.record(z.string(), z.number()).superRefine(async (rec, ctx) => {
for (const k of Object.keys(rec)) {
if (k.includes(' ')) ctx.addIssue({ code: 'custom', message: `bad key ${k}`, path: [k] });
}
}); Defensive patterns
Strategy: type-guard
Validate before calling
function isSyncSchema(s) {
const r = s._zod.run({ value: '__probe__', issues: [] }, undefined);
return !(r instanceof Promise);
}
if (!isSyncSchema(keyType)) throw new Error('key schema is async; records require sync keys'); Type guard
function isSyncKeySchema(s): boolean {
const r = s._zod?.run?.({ value: '', issues: [] });
return r === undefined || !(r instanceof Promise);
} Try / catch
try {
z.record(keyType, valueType).parse(input);
} catch (e) {
if (e instanceof Error && e.message === 'Async schemas not supported in object keys currently') {
// make keyType sync, or move async logic to a superRefine on the record
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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)`.
Common situations: 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.
Related errors
- Synchronous parse encountered promise.
- Async refinement encountered during synchronous parse operat
- Asynchronous transform encountered during synchronous parse
- Map cannot be represented in JSON Schema
- Invalid discriminated union option at index "${def.options.i
AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03).
Data as JSON: /data/errors/d67f720d670fe524.json.
Report an issue: GitHub.