{"record":{"id":"ac8358f47d00bcad","repo":"toeverything/AFFiNE","slug":"a-curve-must-have-at-least-three-points","errorCode":null,"errorMessage":"A curve must have at least three points.","messagePattern":"A curve must have at least three points\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"blocksuite/affine/blocks/surface/src/utils/points-on-curve/curve-to-bezier.ts","lineNumber":13,"sourceCode":"import type { Point } from '../rough/geometry.js';\n\nfunction clone(p: Point): Point {\n  return [...p] as Point;\n}\n\nexport function curveToBezier(\n  pointsIn: readonly Point[],\n  curveTightness = 0\n): Point[] {\n  const len = pointsIn.length;\n  if (len < 3) {\n    throw new Error('A curve must have at least three points.');\n  }\n  const out: Point[] = [];\n  if (len === 3) {\n    out.push(\n      clone(pointsIn[0]),\n      clone(pointsIn[1]),\n      clone(pointsIn[2]),\n      clone(pointsIn[2])\n    );\n  } else {\n    const points: Point[] = [];\n    points.push(pointsIn[0], pointsIn[0]);\n    for (let i = 1; i < pointsIn.length; i++) {\n      points.push(pointsIn[i]);\n      if (i === pointsIn.length - 1) {\n        points.push(pointsIn[i]);\n      }\n    }","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/affine/blocks/surface/src/utils/points-on-curve/curve-to-bezier.ts#L1-L31","documentation":"After enum handling, the validator compares the runtime type of the value (via inputType — objects/arrays/null become 'json') with the schema-declared field type; a mismatch throws with both the expected and received type names. undefined values are dropped earlier and null is only allowed for optional fields, so this fires on present, non-null values of the wrong JS type.","triggerScenarios":"Inserting a string into a field declared type: 'number' (id: '123' from a URL param); booleans into 'string' fields; Date objects into 'string' fields; arrays/objects into scalar fields while the schema says 'string' rather than 'json'.","commonSituations":"URL/query params and form inputs yielding strings; JSON round-trips losing number types; schema types written to match one layer while another layer produces different runtime types.","solutions":["Coerce the value to the declared type before writing (Number(id), String(x))","Fix the schema declaration if it was wrong (e.g. the field genuinely holds string ids, declare type: 'string')","Validate at the boundary: a small typeof-per-schema-field check before the write gives a clearer stack"],"exampleFix":"// before\ntable.insert({ data: { id: 'a1', count: '42' } }); // schema: count is 'number'\n\n// after\ntable.insert({ data: { id: 'a1', count: 42 } });\n// or coerce at the boundary: { ...dto, count: Number(dto.count) }","handlingStrategy":"type-guard","validationCode":"null","typeGuard":"function matchesFieldType(value: unknown, type: FieldType): boolean {\n  const actual =\n    value === null || Array.isArray(value) || typeof value === 'object' ? 'json' : typeof value;\n  return actual === type;\n}\n\n// before writing:\nfor (const [key, field] of Object.entries(table.schema)) {\n  if (data[key] !== undefined && data[key] !== null && !matchesFieldType(data[key], field.type)) {\n    throw new Error(`${key}: expected ${field.type}, got ${typeof data[key]}`);\n  }\n}","tryCatchPattern":null,"preventionTips":["Coerce at the boundary: Number() for numeric fields, String() for text arriving from URL params or forms","Keep schema type declarations in sync with the runtime types the writing layer actually produces","Remember objects/arrays/null are treated as 'json' — declare such fields type: 'json', not 'string'"],"tags":["orm","database","schema-validation","type-mismatch"],"backgroundTag":"field-type-mismatch","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}