windmill-labs/windmill · error · Error
Invalid note at index ${index}: position must be an object w
Error message
Invalid note at index ${index}: position must be an object with numeric x and y What it means
validateFlowNotes validates each note in the AI copilot's flow-tools `notes` argument before the notes are attached to the flow. A note may optionally carry a `position` for explicit placement; when present it must be a plain object with numeric `x` and `y` fields. The library throws this error when the position fails that shape check, so malformed geometry from the LLM never reaches the flow editor.
Source
Thrown at frontend/src/lib/components/copilot/chat/flow/helperUtils.ts:201
if (type !== 'free' && type !== 'group') {
throw new Error(`Invalid note at index ${index}: type must be "free" or "group"`)
}
if (n.color !== undefined && n.color !== null) {
if (typeof n.color !== 'string' || !ALLOWED_NOTE_COLORS.has(n.color)) {
throw new Error(
`Invalid note at index ${index}: color must be one of ${[...ALLOWED_NOTE_COLORS].join(', ')}`
)
}
}
if (n.position !== undefined && n.position !== null) {
const p = n.position as Record<string, unknown>
if (
typeof p !== 'object' ||
Array.isArray(n.position) ||
typeof p.x !== 'number' ||
typeof p.y !== 'number'
) {
throw new Error(
`Invalid note at index ${index}: position must be an object with numeric x and y`
)
}
}
if (n.size !== undefined && n.size !== null) {
const s = n.size as Record<string, unknown>
if (
typeof s !== 'object' ||
Array.isArray(n.size) ||
typeof s.width !== 'number' ||
typeof s.height !== 'number'
) {
throw new Error(
`Invalid note at index ${index}: size must be an object with numeric width and height`
)
}
}
if (type === 'group' && n.contained_node_ids !== undefined) {View on GitHub (pinned to e474e8803c)
Solutions
- Convert coordinates to numbers and pass a plain object: position: { x: Number(x), y: Number(y) }.
- If the position arrives as an array [x, y], spread it into an object: { x: arr[0], y: arr[1] }.
- Omit `position` entirely (or set it to null) to let the validator auto-place the note.
- Check the index in the error message and log the offending note to confirm which field is malformed.
Example fix
// before
notes: [{ id: 'n1', text: 'review', position: [10, 20] }]
// after
notes: [{ id: 'n1', text: 'review', position: { x: 10, y: 20 } }] Defensive patterns
Strategy: validation
Validate before calling
function hasValidPosition(n) {
return n.position == null ||
(typeof n.position === 'object' && !Array.isArray(n.position) &&
typeof n.position.x === 'number' && typeof n.position.y === 'number')
}
notes.forEach((n, i) => { if (!hasValidPosition(n)) throw new Error(`note ${i}: bad position`) }) Type guard
function isPosition(p): p is { x: number; y: number } {
return typeof p === 'object' && p !== null && !Array.isArray(p) &&
typeof (p as any).x === 'number' && typeof (p as any).y === 'number'
} Try / catch
try {
validateFlowNotes(notes)
} catch (e) {
if (e.message.includes('position')) console.warn('dropping note position, will auto-place')
} Prevention
- Always build position as { x: number, y: number }, never arrays or strings
- Coerce LLM-emitted coordinates with Number() before passing
- Omit position when auto-placement is acceptable
When it happens
Trigger: Calling the flow-tools note/flowTools entry point with notes[i].position set to a string like "{x:0,y:0}", an array like [0,0], or an object with string values ({x: "10", y: "20"}) or missing one coordinate.
Common situations: An LLM emits position coordinates as strings in the JSON tool call; the caller hand-builds notes and passes a tuple [x, y] instead of {x, y}; JSON containing coordinates gets re-parsed with number-coercion lost.
Related errors
- Invalid note at index ${index}: size must be an object with
- Invalid note at index ${index}: contained_node_ids must be a
- Invalid flow modules:\n${errors.join('\n')}
- Invalid failure_module: only "rawscript" and "script" module
- Flow notes must be an array
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/988077f2fb7c92ce.
Report an issue: GitHub.