{"record":{"id":"04eadb34d3081fe8","repo":"toeverything/AFFiNE","slug":"param-not-a-number-mode-numbetoken-text","errorCode":null,"errorMessage":"Param not a number: ${mode},${numbeToken.text}","messagePattern":"Param not a number: (.+?),(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"blocksuite/affine/blocks/surface/src/utils/path-data-parser/parser.ts","lineNumber":103,"sourceCode":"        paramsCount = PARAMS[token.text];\n        mode = token.text;\n      } else {\n        return parsePath('M0,0' + d);\n      }\n    } else if (isType(token, NUMBER)) {\n      paramsCount = PARAMS[mode];\n    } else {\n      index++;\n      paramsCount = PARAMS[token.text];\n      mode = token.text;\n    }\n    if (index + paramsCount < tokens.length) {\n      for (let i = index; i < index + paramsCount; i++) {\n        const numbeToken = tokens[i];\n        if (isType(numbeToken, NUMBER)) {\n          params[params.length] = +numbeToken.text;\n        } else {\n          throw new Error(\n            'Param not a number: ' + mode + ',' + numbeToken.text\n          );\n        }\n      }\n      if (typeof PARAMS[mode] === 'number') {\n        const segment: Segment = { key: mode, data: params };\n        segments.push(segment);\n        index += paramsCount;\n        token = tokens[index];\n        if (mode === 'M') mode = 'L';\n        if (mode === 'm') mode = 'l';\n      } else {\n        throw new Error('Bad segment: ' + mode);\n      }\n    } else {\n      throw new Error('Path data ended short');\n    }\n  }","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/affine/blocks/surface/src/utils/path-data-parser/parser.ts#L85-L121","documentation":"The PrimaryKeyShouldNotBeUpdated validator rejects update payloads that include the key field at all — any value, even an unchanged one. The primary key addresses rows inside the adapters' key maps, so mutating it mid-update could orphan data; updates must identify the row (where clause) and change only non-key fields.","triggerScenarios":"Passing a whole entity object including id to an update API instead of a partial patch; building the update payload with spread { ...entity, name: 'new' }; reusing an insert object as the update payload.","commonSituations":"REST-style handlers that PUT full objects; form state round-trips that carry ids; generic save() functions shared by insert and update paths.","solutions":["Strip the key from the update payload: const { [keyField]: _, ...patch } = entity before validating/sending","Separate insert vs update code paths so update always receives a partial patch plus the key in the where clause","Add a dev-mode assertion that patch[table.keyField] === undefined"],"exampleFix":"// before\ntable.update({ where: { byKey: id }, data: entity }); // entity still contains id\n\n// after\nconst { id: _key, ...patch } = entity;\ntable.update({ where: { byKey: id }, data: patch });","handlingStrategy":"validation","validationCode":"function toPatch(keyField: string, entity: Record<string, any>) {\n  const { [keyField]: _drop, ...patch } = entity;\n  return patch;\n}\ntable.update({ where: { byKey: id }, data: toPatch('id', entity) });","typeGuard":"null","tryCatchPattern":null,"preventionTips":["Never pass a whole entity to update — strip the key field into a partial patch","Keep insert and update paths separate; update identifies rows via where, changes only non-key fields","Add a dev-mode assertion that the update payload has no key field"],"tags":["orm","database","primary-key","update","validation"],"backgroundTag":"immutable-primary-key-update","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"}