{"record":{"id":"4d969a6013d76927","repo":"windmill-labs/windmill","slug":"invalid-note-at-index-index-contained-node-ids","errorCode":null,"errorMessage":"Invalid note at index ${index}: contained_node_ids must be an array of strings","messagePattern":"Invalid note at index (.+?): contained_node_ids must be an array of strings","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/flow/helperUtils.ts","lineNumber":224,"sourceCode":"\t\tif (n.size !== undefined && n.size !== null) {\n\t\t\tconst s = n.size as Record<string, unknown>\n\t\t\tif (\n\t\t\t\ttypeof s !== 'object' ||\n\t\t\t\tArray.isArray(n.size) ||\n\t\t\t\ttypeof s.width !== 'number' ||\n\t\t\t\ttypeof s.height !== 'number'\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid note at index ${index}: size must be an object with numeric width and height`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tif (type === 'group' && n.contained_node_ids !== undefined) {\n\t\t\tif (\n\t\t\t\t!Array.isArray(n.contained_node_ids) ||\n\t\t\t\tn.contained_node_ids.some((id) => typeof id !== 'string')\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid note at index ${index}: contained_node_ids must be an array of strings`\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (moduleIds) {\n\t\t\t\tfor (const id of n.contained_node_ids as string[]) {\n\t\t\t\t\tif (!moduleIds.has(id)) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`Invalid note at index ${index}: contained_node_ids \"${id}\" does not match any flow module`\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst normalized = {\n\t\t\t...(n as FlowNote),\n\t\t\ttype,\n\t\t\t// Preserve a provided color; only seed the default when omitted.\n\t\t\tcolor: typeof n.color === 'string' ? n.color : DEFAULT_NOTE_COLOR","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/flow/helperUtils.ts#L206-L242","documentation":"For notes of type \"group\", validateFlowNotes optionally accepts `contained_node_ids`, the list of flow module ids the group visually wraps. When the field is provided it must be an array whose every element is a string; otherwise this error is thrown.","triggerScenarios":"Calling the note/flowTools tool with a type:\"group\" note whose contained_node_ids is a single string \"a,b\", a comma-split array containing non-strings like [\"a\", 42], or an object instead of an array.","commonSituations":"The LLM joins ids into one comma-separated string; ids get mixed with numeric indexes from a table; the caller passes the raw module list (objects) instead of the id strings.","solutions":["Ensure contained_node_ids is an array of strings: [\"mod1\", \"mod2\"].","Map module objects to their ids: contained_node_ids: modules.map((m) => m.id).","Omit contained_node_ids to let the group be defined without explicit membership.","Verify the note type is \"group\" — this check only runs for group notes."],"exampleFix":"// before\n{ id: 'g1', type: 'group', text: 'step', contained_node_ids: 'a,b' }\n// after\n{ id: 'g1', type: 'group', text: 'step', contained_node_ids: ['a', 'b'] }","handlingStrategy":"type-guard","validationCode":"if (note.type === 'group' && note.contained_node_ids !== undefined) {\n  const ok = Array.isArray(note.contained_node_ids) &&\n    note.contained_node_ids.every((id) => typeof id === 'string')\n  if (!ok) throw new Error('contained_node_ids must be string[]')\n}","typeGuard":"function isStringArray(v): v is string[] {\n  return Array.isArray(v) && v.every((x) => typeof x === 'string')\n}","tryCatchPattern":"try {\n  validateFlowNotes(notes, moduleIds)\n} catch (e) {\n  if (e.message.includes('contained_node_ids')) {\n    notes = notes.map((n) => ('contained_node_ids' in n ? { ...n, contained_node_ids: String(n.contained_node_ids).split(',') } : n))\n  }\n}","preventionTips":["Pass ids as an array of strings, never a joined string","Map module objects to their id strings before building the note","Only set contained_node_ids on notes with type \"group\""],"tags":["validation","typescript","flow-notes","schema"],"backgroundTag":"invalid-tool-argument-shape","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"}