Zema Logo
Schemas

Map

Validate dynamic Map<K, V> values with ZemaMap: key and value schemas, size constraints, and typed output.

Validates Map values where every key and every value are validated by their respective schemas. Produces a typed Map<K, V>. Validation is exhaustive, all entry failures are collected before returning.

Signature:

ZemaMap<K, V> map<K, V>(ZemaSchema<dynamic, K> keySchema, ZemaSchema<dynamic, V> valueSchema)

Validation order: type check → size constraints → entry validation (exhaustive).

If a size constraint fails, entry validation is skipped entirely.


ZemaMap vs ZemaObject

z.map()z.object()
KeysDynamic — any number, validated uniformlyFixed — defined in the shape
Use caseDictionaries, lookup tablesStructured records
Output typeMap<K, V>Map<String, dynamic> or T

Basic usage

// String keys → integer values
final scoreSchema = z.map(
  z.string(),
  z.integer().gte(0),
);

scoreSchema.parse({'alice': 95, 'bob': 87});
// Map<String, int>: {'alice': 95, 'bob': 87}

scoreSchema.parse({'alice': 95, 'bob': -1});
// throws ZemaException: too_small at path 'bob'

Key constraints

Any schema can be used as the key schema:

// Non-empty string keys only
final headers = z.map(
  z.string().min(1),
  z.string(),
);

headers.parse({'': 'value'});
// throws ZemaException: too_short at path ''

Size constraints

.min(n)

Requires the map to have at least n entries. Produces too_small.

z.map(z.string(), z.integer()).min(1)   // non-empty

schema.parse({});        // throws ZemaException: too_small
schema.parse({'a': 1});  // Map<String, int>: {'a': 1}

.max(n)

Requires the map to have at most n entries. Produces too_big.

z.map(z.string(), z.string()).max(50)

Error paths

Entry-level issues include the entry's key in their path:

final schema = z.map(z.string(), z.integer());
final result = schema.safeParse({'a': 1, 'b': 'bad'});

// ZemaIssue(code: 'invalid_type', path: ['b'], ...)
// → value at key 'b' failed

issue.pathString formats this as 'b'.


Common patterns

User scores

final scoresSchema = z.map(
  z.string().uuid(),      // user ID as key
  z.integer().gte(0).lte(100),  // score as value
);

scoresSchema.parse({
  '550e8400-e29b-41d4-a716-446655440000': 87,
  'a3bb189e-8bf9-3888-9912-ace4e6543002': 92,
});

HTTP headers

final headersSchema = z.map(
  z.string().min(1),
  z.string(),
);

headersSchema.parse({
  'Content-Type': 'application/json',
  'Authorization': 'Bearer token',
});

Feature flags

final flagsSchema = z.map(
  z.string(),
  z.boolean(),
).min(1);

flagsSchema.parse({
  'dark_mode': true,
  'beta_features': false,
});

Translations

final translationsSchema = z.map(
  z.string().regex(RegExp(r'^[a-z]{2}$')),  // ISO 639-1 locale
  z.string().min(1),
);

translationsSchema.parse({
  'en': 'Hello',
  'fr': 'Bonjour',
  'de': 'Hallo',
});

Error codes

CodeTrigger
invalid_typeInput is not a Map.
too_smallEntry count below .min().
too_bigEntry count above .max().

Plus any error codes produced by keySchema or valueSchema.


API reference

MethodDescriptionError code
.min(n)Minimum n entries.too_small
.max(n)Maximum n entries.too_big
.optional()Allow null input.
.withDefault(v)Substitute null with v.

Next steps

  • Objects: fixed-shape map validation
  • Union: accept multiple types
Copyright © 2026