{"record":{"id":"74a2adcb94b76b16","repo":"FlowiseAI/Flowise","slug":"number-of-keys-keystrings-length-does-not-mat","errorCode":null,"errorMessage":"Number of keys (${keyStrings.length}) does not match number of group_ids (${groupIds.length})","messagePattern":"Number of keys \\((.+?)\\) does not match number of group_ids \\((.+?)\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/components/nodes/recordmanager/MySQLRecordManager/MySQLrecordManager.ts","lineNumber":317,"sourceCode":"        const queryRunner = dataSource.createQueryRunner()\n        const tableName = this.sanitizeTableName(this.tableName)\n\n        const updatedAt = await this.getTime()\n        const { timeAtLeast, groupIds: _groupIds } = updateOptions ?? {}\n\n        if (timeAtLeast && updatedAt < timeAtLeast) {\n            throw new Error(`Time sync issue with database ${updatedAt} < ${timeAtLeast}`)\n        }\n\n        // Handle both new format (objects with uid and docId) and old format (strings)\n        const isNewFormat = keys.length > 0 && typeof keys[0] === 'object' && 'uid' in keys[0]\n        const keyStrings = isNewFormat ? (keys as Array<{ uid: string; docId: string }>).map((k) => k.uid) : (keys as string[])\n        const docIds = isNewFormat ? (keys as Array<{ uid: string; docId: string }>).map((k) => k.docId) : keys.map(() => null)\n\n        const groupIds = _groupIds ?? keyStrings.map(() => null)\n\n        if (groupIds.length !== keyStrings.length) {\n            throw new Error(`Number of keys (${keyStrings.length}) does not match number of group_ids (${groupIds.length})`)\n        }\n\n        const recordsToUpsert = keyStrings.map((key, i) => [key, this.namespace, updatedAt, groupIds[i] ?? null, docIds[i] ?? null])\n\n        const query = `\n            INSERT INTO \\`${tableName}\\` (\\`key\\`, \\`namespace\\`, \\`updated_at\\`, \\`group_id\\`, \\`doc_id\\`)\n            VALUES (?, ?, ?, ?, ?)\n            ON DUPLICATE KEY UPDATE \\`updated_at\\` = VALUES(\\`updated_at\\`), \\`doc_id\\` = VALUES(\\`doc_id\\`)`\n\n        // To handle multiple files upsert\n        try {\n            for (const record of recordsToUpsert) {\n                // Consider using a transaction for batch operations\n                await queryRunner.manager.query(query, record.flat())\n            }\n\n            await queryRunner.release()\n        } catch (error) {","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/nodes/recordmanager/MySQLRecordManager/MySQLrecordManager.ts#L299-L335","documentation":"Thrown inside MySQLRecordManager.update after groupIds is resolved from updateOptions. The record manager writes one group_id per key, so the arrays must be equal in length. If a caller supplies groupIds explicitly with a different count than keys, the upsert would misalign rows, so it aborts.","triggerScenarios":"Passing updateOptions.groupIds as an array whose length differs from the keys array; passing keys as objects-with-uid but groupIds sized for a different batch; a partial pipeline that filters keys without filtering groupIds.","commonSituations":"Upstream code slices keys (.slice(0, 10)) but forgets to slice groupIds; merging two sources where one contributed extra keys; off-by-one when zipping keys and groupIds.","solutions":["Ensure groupIds.length === keys.length before calling update; if you don't need group ids, omit groupIds entirely and the manager defaults each to null.","Zip the two arrays at the source: keys.map((k,i) => ({k, g: groupIds[i]})) and filter together.","If groupIds is optional, pass undefined rather than a mismatched array."],"exampleFix":"// before\nawait mgr.update(keys, { groupIds: someGroupIds })  // lengths differ\n// after\nawait mgr.update(keys, { groupIds: keys.map((_, i) => groupIds[i] ?? null) })","handlingStrategy":"validation","validationCode":"function validateKeysAndGroupIds(keys: unknown[], groupIds?: unknown[]): void {\n  if (groupIds && groupIds.length !== keys.length) {\n    throw new Error(`groupIds length (${groupIds.length}) must equal keys length (${keys.length})`)\n  }\n}","typeGuard":"function areAligned(keys: unknown[], groupIds: unknown[] | undefined): boolean {\n  return !groupIds || groupIds.length === keys.length\n}","tryCatchPattern":"try {\n  await manager.update(keys, { groupIds })\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Number of keys')) {\n    // drop groupIds and retry, or realign upstream\n  }\n  throw e\n}","preventionTips":["Zip keys and groupIds at the source and filter them as pairs.","Default groupIds to undefined (manager fills nulls) when you don't need per-key groups.","Add a length-equality assertion in your pipeline harness."],"tags":["mysql","record-manager","validation","array-length","upsert"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}