Skip to content

A Record<string, T> reference makes a recursive discriminated union with an array branch reject valid array values ("must be an array (was object)") β€” regression in 2.2.2Β #1640

Description

@karolrybak

Report a bug

πŸ”Ž Search Terms

=== query: must be an array ===
=== query: discriminated union Record ===
=== query: recursive union ===
=== query: Record discriminated ===
=== query: was object ===

🧩 Context

arktype @ark/schema result
2.2.1 0.56.0 βœ… OK
2.2.2 0.56.1 ❌ ERR
2.2.3 0.56.2 ❌ ERR

The regression is introduced in 2.2.2 (@ark/schema 0.56.0 β†’ 0.56.1).

πŸ§‘β€πŸ’» Repro

import { scope, type } from "arktype";

const Node = scope({
  Number: { type: "'number'" },
  Array:  { type: "'array'", item: "Node" },
  Unit:   { type: "'unit'" },
  Container: { things: "Record<string, Node>" }, // ← remove this line β†’ works
  Node: "Number | Array | Unit",
}).export().Node;

// A perfectly valid Node of the `array` variant:
const out = Node({ type: "array", item: { type: "number" } });

console.log(out instanceof type.errors ? "ERR: " + out.summary : "OK");
// 2.2.1 β†’ "OK"
// 2.2.2 / 2.2.3 β†’ "ERR: must be an array (was object)"

Minimization notes

The bug requires all of:

  1. a discriminated union with β‰₯ 3 branches (2 branches do not trigger it);
  2. one branch being an array type whose item recurses into the union
    ({ type: "'array'", item: "Node" });
  3. a Record<string, Node> reference somewhere in the same scope.

Remove (3), or drop to 2 branches β†’ the same value validates fine. It does not
depend on validation order β€” the mis-resolution is baked in at scope-build time.

Possibly related

This is the same fragile area as cyclic/recursive discriminated-union
discrimination:

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

Status
To do

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions