{"record":{"id":"a07b6d7d770242ab","repo":"toeverything/AFFiNE","slug":"table-table-name-field-key-type-mismat-a07b6d","errorCode":null,"errorMessage":"[Table(${table.name})]: Field '${key}' type mismatch. Expected type '${field.type}' but got '${typeGet}'.","messagePattern":"\\[Table\\((.+?)\\)\\]: Field '(.+?)' type mismatch\\. Expected type '(.+?)' but got '(.+?)'\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/common/infra/src/orm/core/validators/data.ts","lineNumber":120,"sourceCode":"\n          if (val === undefined || val === null) {\n            if (!field.optional) {\n              throw new Error(\n                `[Table(${table.name})]: Field '${key}' is required but not set.`\n              );\n            }\n            continue;\n          }\n\n          const typeGet = inputType(val);\n          if (field.type === 'enum') {\n            if (!field.values?.includes(val)) {\n              throw new Error(\n                `[Table(${table.name})]: Field '${key}' value '${val}' is not valid. Expected one of [${field.values?.join(', ')}].`\n              );\n            }\n          } else if (!typeMatches(field.type, typeGet)) {\n            throw new Error(\n              `[Table(${table.name})]: Field '${key}' type mismatch. Expected type '${field.type}' but got '${typeGet}'.`\n            );\n          }\n\n          keys.add(key);\n        } else if (!table.isDocumentTable) {\n          // strict check field existence for normal table\n          throw new Error(\n            `[Table(${table.name})]: Field '${key}' is not defined but set in entity.`\n          );\n        }\n      }\n\n      for (const key in table.schema) {\n        if (!keys.has(key) && table.schema[key].optional === false) {\n          throw new Error(\n            `[Table(${table.name})]: Field '${key}' is required but not set.`\n          );","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/common/infra/src/orm/core/validators/data.ts#L102-L138","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Coerce the value to the declared type before insert: Number(x) for number fields, String(x) or template literals for string fields.","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).","Add a TypeScript type on the create payload (the table's inferred types) so the compiler catches this before runtime.","Check nested values: a single wrong property inside an object field reported by key still points at the exact field name in the message."],"exampleFix":"// before\nawait db.doc.create({ id, title: 123 }); // title is t.string()\n\n// after\nawait db.doc.create({ id, title: String(123) });\n// better: type the payload from the table so tsc complains first","handlingStrategy":"type-guard","validationCode":"function matchesDeclaredType(type: string, v: unknown): boolean {\n  switch (type) {\n    case 'string': return typeof v === 'string';\n    case 'number': return typeof v === 'number' && Number.isFinite(v);\n    case 'boolean': return typeof v === 'boolean';\n    default: return true; // json/other: assume valid, let server/validator decide\n  }\n}","typeGuard":"const isStr = (v: unknown): v is string => typeof v === 'string';\nconst isNum = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v);\nconst isBool = (v: unknown): v is boolean => typeof v === 'boolean';","tryCatchPattern":"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; }","preventionTips":["Coerce URL/localStorage/form values before insert (Number(), String())","Let TypeScript infer payload types from the table schema","Watch out for JSON round-trips turning numbers into strings"],"tags":["orm","validation","type-mismatch","affine"],"backgroundTag":"type-mismatch","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}