zod icon indicating copy to clipboard operation
zod copied to clipboard

Impossible parsing of `z.record(z.number(), z.any())`

Open msanchezdev opened this issue 1 week ago • 2 comments

Because keys are always strings in Javascript, a record will never parse when the schema specifies it should be a number.

const schema = z.record(z.number(), z.number());
schema.parse({ 1: 100, 2: 88, 3: 99, 4: 60 })

A workaround or the right way would be to coerce the number instead:

const schema = z.record(z.coerce.number(), z.number());
schema.parse({ 1: 100, 2: 88, 3: 99, 4: 60 })

Only problem being the record throwing type error as the coerced number doesnt have a number input.

msanchezdev avatar Dec 11 '25 00:12 msanchezdev

📝 CodeRabbit Plan Mode

Generate an implementation plan and agent prompts for this issue.

  • [ ] Create Plan
Examples

🔗 Similar Issues

Possible Duplicates

Related Issues

👤 Suggested Assignees

  • RobinTail
  • LorisSigrist
  • dinfer
  • bakura10
  • MichaelBitard

🧪 Issue enrichment is currently in early access.

To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

issue_enrichment:
  auto_enrich:
    enabled: false

coderabbitai[bot] avatar Dec 11 '25 00:12 coderabbitai[bot]

You're right—z.record(z.number(), ...) doesn't work as expected because JavaScript object keys are always strings, so Zod can't validate them as numbers at runtime. Even if you use z.coerce.number() as the key schema, the keys are still strings, and while coercion will convert them to numbers during parsing, the resulting object will still have string keys. This also causes a TypeScript type error because ZodCoercedNumber isn't assignable to the expected key type for records in Zod, and the input type for coercion is unknown by default [docs](https://zod.dev/api) [issue](https://github.com/colinhacks/zod/issues/4383).

The recommended approach is to use z.record(z.string(), ...) if you want to work with plain objects, or switch to z.map(z.number(), ...) if you truly need numeric keys, since Map supports non-string keys [docs](https://zod.dev/api?id=maps).

If you need to coerce keys to numbers for validation, you can preprocess or transform the keys yourself, or use a workaround like validating keys as strings and then piping to z.coerce.number() or a transform pipeline, e.g. z.any().transform(Number).pipe(z.number()) [discussion](https://github.com/colinhacks/zod/issues/2172).

This behavior is intentional and documented—using number keys in records is not recommended in Zod. If this answers your question, please close the issue. If you need more help, feel free to provide a runnable reproduction!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

dosubot[bot] avatar Dec 11 '25 00:12 dosubot[bot]