toeverything/AFFiNE · error · Error

[Table(${table.name})]: Field '${key}' type mismatch. Expect

Error message

[Table(${table.name})]: Field '${key}' type mismatch. Expected type '${field.type}' but got '${typeGet}'.

What it means

Thrown by the ORM's DataTypeShouldExactlyMatch validator when a value's runtime type (via inputType()) does not match the field's declared t.type(). Only enum fields skip this check (they get error 701 instead). This is a strict, non-coercing type check: '5' will not satisfy a number field.

Source

Thrown at packages/common/infra/src/orm/core/validators/data.ts:120

          if (val === undefined || val === null) {
            if (!field.optional) {
              throw new Error(
                `[Table(${table.name})]: Field '${key}' is required but not set.`
              );
            }
            continue;
          }

          const typeGet = inputType(val);
          if (field.type === 'enum') {
            if (!field.values?.includes(val)) {
              throw new Error(
                `[Table(${table.name})]: Field '${key}' value '${val}' is not valid. Expected one of [${field.values?.join(', ')}].`
              );
            }
          } else if (!typeMatches(field.type, typeGet)) {
            throw new Error(
              `[Table(${table.name})]: Field '${key}' type mismatch. Expected type '${field.type}' but got '${typeGet}'.`
            );
          }

          keys.add(key);
        } else if (!table.isDocumentTable) {
          // strict check field existence for normal table
          throw new Error(
            `[Table(${table.name})]: Field '${key}' is not defined but set in entity.`
          );
        }
      }

      for (const key in table.schema) {
        if (!keys.has(key) && table.schema[key].optional === false) {
          throw new Error(
            `[Table(${table.name})]: Field '${key}' is required but not set.`
          );

View on GitHub (pinned to b4c8548c09)

Solutions

  1. Coerce the value to the declared type before insert: Number(x) for number fields, String(x) or template literals for string fields.
  2. Fix the schema if the runtime type is actually correct and the declaration is stale (e.g. the column now stores structured data → switch to t.json-compatible type).
  3. Add a TypeScript type on the create payload (the table's inferred types) so the compiler catches this before runtime.
  4. Check nested values: a single wrong property inside an object field reported by key still points at the exact field name in the message.

Example fix

// before
await db.doc.create({ id, title: 123 }); // title is t.string()

// after
await db.doc.create({ id, title: String(123) });
// better: type the payload from the table so tsc complains first
Defensive patterns

Strategy: type-guard

Validate before calling

function matchesDeclaredType(type: string, v: unknown): boolean {
  switch (type) {
    case 'string': return typeof v === 'string';
    case 'number': return typeof v === 'number' && Number.isFinite(v);
    case 'boolean': return typeof v === 'boolean';
    default: return true; // json/other: assume valid, let server/validator decide
  }
}

Type guard

const isStr = (v: unknown): v is string => typeof v === 'string';
const isNum = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v);
const isBool = (v: unknown): v is boolean => typeof v === 'boolean';

Try / catch

try { await db.doc.create(payload); } catch (e) { if (e instanceof Error && e.message.includes('type mismatch')) { /* coerce the named field and retry once */ } throw e; }

Prevention

When it happens

Trigger: Passing '5' (string) to t.number(), 5 (number) to t.string(), an array/object to a scalar field, or a boolean where the schema says 'string'. Also fires for JSON-typed fields when inputType()'s classification of the value differs from the declared type.

Common situations: Values coming from URL query params, localStorage, or GraphQL variables that are always strings; form inputs that yield strings for numeric fields; JSON.parse'd payloads where a number was serialized as string; switching a field type in the schema without updating the code that writes it.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18). Data as JSON: /api/errors/a07b6d7d770242ab. Report an issue: GitHub.