{"record":{"id":"87ead04620936dee","repo":"windmill-labs/windmill","slug":"invalid-note-at-index-index-type-must-be-free","errorCode":null,"errorMessage":"Invalid note at index ${index}: type must be \"free\" or \"group\"","messagePattern":"Invalid note at index (.+?): type must be \"free\" or \"group\"","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/flow/helperUtils.ts","lineNumber":184,"sourceCode":"\tlet autoStackY = 0\n\treturn rawNotes.map((note, index) => {\n\t\tif (!note || typeof note !== 'object' || Array.isArray(note)) {\n\t\t\tthrow new Error(`Invalid note at index ${index}: must be an object`)\n\t\t}\n\t\tconst n = note as Record<string, unknown>\n\t\tif (typeof n.id !== 'string' || !n.id) {\n\t\t\tthrow new Error(`Invalid note at index ${index}: id must be a non-empty string`)\n\t\t}\n\t\tif (seenIds.has(n.id)) {\n\t\t\tthrow new Error(`Invalid note at index ${index}: duplicate note id \"${n.id}\"`)\n\t\t}\n\t\tseenIds.add(n.id)\n\t\tif (typeof n.text !== 'string') {\n\t\t\tthrow new Error(`Invalid note at index ${index}: text must be a string`)\n\t\t}\n\t\tconst type = n.type ?? 'free'\n\t\tif (type !== 'free' && type !== 'group') {\n\t\t\tthrow new Error(`Invalid note at index ${index}: type must be \"free\" or \"group\"`)\n\t\t}\n\t\tif (n.color !== undefined && n.color !== null) {\n\t\t\tif (typeof n.color !== 'string' || !ALLOWED_NOTE_COLORS.has(n.color)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid note at index ${index}: color must be one of ${[...ALLOWED_NOTE_COLORS].join(', ')}`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tif (n.position !== undefined && n.position !== null) {\n\t\t\tconst p = n.position as Record<string, unknown>\n\t\t\tif (\n\t\t\t\ttypeof p !== 'object' ||\n\t\t\t\tArray.isArray(n.position) ||\n\t\t\t\ttypeof p.x !== 'number' ||\n\t\t\t\ttypeof p.y !== 'number'\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid note at index ${index}: position must be an object with numeric x and y`","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/flow/helperUtils.ts#L166-L202","documentation":"The only accepted note types are 'free' (standalone canvas annotation, the default) and 'group' (deprecated for creation but still accepted for round-tripping existing flows). validateFlowNotes throws this error when note.type is any other value.","triggerScenarios":"notes: [{ id: 'n1', text: 'x', type: 'sticky' }] or type: 'Free' (wrong case) or type: 'annotation' passed to patch_flow_json/set_flow_json.","commonSituations":"An LLM agent invents a type name; capitalization mismatch; an agent tries to create the deprecated 'group' notes under a new name instead of using the groups array.","solutions":["Use type: 'free' (or omit type, which defaults to 'free') for standalone notes","Use type: 'group' only for pre-existing group notes; prefer the separate groups array for new groupings","Fix casing — the comparison is exact lowercase"],"exampleFix":"// before\nnotes: [{ id: 'n1', text: 'x', type: 'sticky' }]\n// after\nnotes: [{ id: 'n1', text: 'x', type: 'free' }] // or omit type","handlingStrategy":"validation","validationCode":"const TYPES = ['free', 'group'];\nnotes.forEach((n, i) => {\n  if (n.type !== undefined && !TYPES.includes(n.type)) throw new Error(`notes[${i}].type \"${n.type}\" invalid`);\n});","typeGuard":"function isValidNoteType(t: unknown): t is 'free' | 'group' {\n  return t === 'free' || t === 'group';\n}","tryCatchPattern":"try {\n  validateFlowNotes(rawNotes, moduleIds);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('type must be')) {\n    // drop the type field (defaults to 'free') and retry\n  } else throw e;\n}","preventionTips":["Omit type for new notes — 'free' is the default and the recommended kind","Never invent type names; only 'free' and the deprecated 'group' are accepted","Use the groups array for grouping logic instead of group-typed notes"],"tags":["validation","flow-notes","enum-value"],"backgroundTag":"invalid-enum-value","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}