Skip to content

schematizer-zod: z.enum fields are silently dropped from TablesSchema #290

@devalbo

Description

@devalbo

Describe the bug

When using createZodSchematizer to derive a TablesSchema from a Zod schema that includes z.enum, the resulting schema silently omits the enum cell. Any value written to that cell via setRow or setCell is rejected without error — the row is created with all other cells intact, but the enum cell is always empty.

Environment

  • tinybase: 8.0.2
  • zod: 4.3.6
  • tinybase/schematizers/schematizer-zod: 8.0.2

Your Example Website or App

No response

Steps to Reproduce the Bug or Issue

No response

Expected behavior

Minimal Reproduction

import { createStore } from 'tinybase';
import { createZodSchematizer } from 'tinybase/schematizers/schematizer-zod';
import { z } from 'zod';

const RatingSchema = z.enum(['up', 'down']);

const RowSchema = z.object({
  id:     z.string(),
  rating: RatingSchema,        // z.enum — affected
  score:  z.number(),
  notes:  z.string().default(''),
});

const schematizer = createZodSchematizer();
const schema = schematizer.toTablesSchema({ ratings: RowSchema });

const store = createStore().setTablesSchema(schema);

store.setRow('ratings', 'row1', {
  id:     'abc',
  rating: 'up',
  score:  42,
  notes:  'looks good',
});

console.log(store.getCell('ratings', 'row1', 'rating')); // undefined — expected: 'up'
console.log(store.getCell('ratings', 'row1', 'score'));  // 42 ✓
console.log(store.getCell('ratings', 'row1', 'id'));     // 'abc' ✓
console.log(store.hasRow('ratings', 'row1'));            // true — row exists, just missing the cell

Expected Behavior

z.enum(['up', 'down']) should map to { type: 'string' } in the derived TablesSchema, the same as z.string(). The cell value 'up' is a valid string and should be stored.

Actual Behavior

The rating cell is absent from the derived schema. The schematizer output confirms it:

{
  "ratings": {
    "id":    { "type": "string" },
    "score": { "type": "number" },
    "notes": { "type": "string", "default": "" }
  }
}

rating never appears. TinyBase then silently drops the rating: 'up' value on write: TinyBase silently rejects the value on write. getCell returns undefined; the row is present but the cell is permanently empty.

Root Cause

The schematizer documentation lists supported primitive types as string, number, and boolean. z.enum is not in this list and appears to produce no entry in the schema rather than falling back to { type: 'string' }. Additionally, Zod v4 moved internal schema definitions from ._def to ._zod.def, which would break any incidental enum detection that relied on Zod internals.

Impact

The failure is completely silent — no error is thrown, no warning is logged, and the row is created successfully. This makes the bug very hard to diagnose: data appears to be written but the enum cell is always empty, and all reactive hooks reading that cell return undefined.

Suggested Fix

Either document that z.enum is unsupported (and ideally warn at schema derivation time), or map z.enum{ type: 'string' } in the schematizer since enum values are always strings at the TinyBase cell level.

Workaround

Bypass the schematizer and define the TablesSchema manually:

const ratingsTablesSchema: TablesSchema = {
  ratings: {
    id:     { type: 'string', default: '' },
    rating: { type: 'string', default: '' }, // z.enum mapped manually
    score:  { type: 'number', default: 0 },
    notes:  { type: 'string', default: '' },
  },
};

Screenshots or Videos

No response

Platform

  • OS: [e.g. macOS, Windows, Linux]
  • Browser: [e.g. Chrome, Safari, Firefox]
  • Version: [e.g. 91.1]

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions