Zema Logo
Schemas

Arrays

Validate List values with ZemaArray: length constraints, nested schemas, transformations, and refinements.

Validates List values. Every element is validated by the element schema. Validation is exhaustive: all element failures are collected before returning.

Signature:

ZemaArray<T> array<T>(ZemaSchema<dynamic, T> element)

Validation order: type check → length constraints → element validation.

If a length constraint fails, element validation is skipped entirely.


Basic usage

final schema = z.array(z.string());

schema.parse(['a', 'b', 'c']);   // ['a', 'b', 'c']
schema.parse([1, 2, 3]);         // throws ZemaException: invalid_type
schema.parse('not an array');    // throws ZemaException: invalid_type

Length constraints

.min(n)

Requires the list to have at least n elements. Produces too_small.

z.array(z.string()).min(2)

schema.parse(['a', 'b']);   // ['a', 'b']
schema.parse(['a']);         // throws ZemaException: too_small

.max(n)

Requires the list to have at most n elements. Produces too_big.

z.array(z.string()).max(5)

schema.parse(['a', 'b', 'c']);                    // ['a', 'b', 'c']
schema.parse(['a', 'b', 'c', 'd', 'e', 'f']);    // throws ZemaException: too_big

.length(n)

Sets both minimum and maximum to n. Produces too_small or too_big.

z.array(z.string()).length(3)

schema.parse(['a', 'b', 'c']);   // ['a', 'b', 'c']
schema.parse(['a', 'b']);         // throws ZemaException

.nonEmpty()

Shorthand for .min(1). Produces too_small on an empty list.

z.array(z.string()).nonEmpty()

schema.parse(['a']);   // ['a']
schema.parse([]);      // throws ZemaException: too_small

Nested arrays

Array of arrays

final schema = z.array(z.array(z.integer()));

schema.parse([
  [1, 2, 3],
  [4, 5, 6],
]);  // [[1, 2, 3], [4, 5, 6]]

schema.parse([
  [1, 2, 3],
  ['a', 'b'],   // invalid: not integers
]);  // throws ZemaException

Array of objects

final schema = z.array(
  z.object({
    'id': z.integer(),
    'name': z.string(),
  }),
);

schema.parse([
  {'id': 1, 'name': 'Alice'},
  {'id': 2, 'name': 'Bob'},
]);  // List<Map<String, dynamic>>

schema.parse([
  {'id': 1, 'name': 'Alice'},
  {'id': 'two', 'name': 'Bob'},   // invalid: id is not int
]);  // throws ZemaException

Error paths

Element-level issues include the element index in their path:

final schema = z.array(z.object({'name': z.string()}));
final result = schema.safeParse([
  {'name': 'Alice'},
  {'name': 42},            // invalid
]);

// ZemaIssue(code: 'invalid_type', path: [1, 'name'], ...)
// → 'name' field of element at index 1

issue.pathString formats this as '[1].name'.


Transformations

// Map elements
final schema = z.array(z.string())
  .transform((list) => list.map((s) => s.toUpperCase()).toList());

schema.parse(['hello', 'world']);   // ['HELLO', 'WORLD']

// Filter elements
final positives = z.array(z.integer())
  .transform((list) => list.where((n) => n > 0).toList());

positives.parse([1, -2, 3, -4, 5]);   // [1, 3, 5]

Refinements

// All elements must be even
final schema = z.array(z.integer())
  .refine(
    (list) => list.every((n) => n % 2 == 0),
    message: 'All numbers must be even',
  );

schema.parse([2, 4, 6]);   // [2, 4, 6]
schema.parse([2, 3, 4]);   // throws ZemaException

// Unique elements
final unique = z.array(z.string())
  .refine(
    (list) => list.length == list.toSet().length,
    message: 'Array must contain unique values',
  );

unique.parse(['a', 'b', 'c']);   // ['a', 'b', 'c']
unique.parse(['a', 'b', 'a']);   // throws ZemaException

Common patterns

Tags

final tagsSchema = z.array(z.string())
  .min(1)
  .max(5)
  .transform((tags) => tags.map((t) => t.toLowerCase()).toList());

tagsSchema.parse(['Flutter', 'Dart', 'Mobile']);
// ['flutter', 'dart', 'mobile']

Optional array with default

final userSchema = z.object({
  'id': z.integer(),
  'email': z.string().email(),
  'roles': z.array(z.string()).withDefault([]),
});

userSchema.parse({
  'id': 1,
  'email': 'alice@example.com',
  // 'roles' absent — defaults to []
});

Paginated response

final paginatedSchema = z.object({
  'items': z.array(z.object({
    'id': z.integer(),
    'title': z.string(),
  })),
  'total': z.integer(),
  'page': z.integer(),
  'perPage': z.integer(),
});

final result = paginatedSchema.safeParse(responseBody);

Error codes

CodeTrigger
invalid_typeInput is not a List.
too_smallLength below .min() or .nonEmpty().
too_bigLength above .max().

API reference

MethodDescription
.min(n)Minimum n elements.
.max(n)Maximum n elements.
.length(n)Exactly n elements.
.nonEmpty()Shorthand for .min(1).
.optional()null input passes through.
.withDefault(v)null input substitutes v.

Next steps

Copyright © 2026