windmill-labs/windmill · error · Error
Flow notes must be an array
Error message
Flow notes must be an array
What it means
validateFlowNotes validates the optional `notes` array attached to a flow update. If rawNotes is neither null/undefined nor an array (e.g. an object or string was passed), this error is thrown. It enforces the FlowNote[] shape the note editor expects before notes are placed on the canvas.
Source
Thrown at frontend/src/lib/components/copilot/chat/flow/helperUtils.ts:156
* `set_flow_json` rather than being rejected. When `moduleIds` is provided,
* every `contained_node_ids` entry of a `group` note must reference an existing
* module.
*
* A provided palette `color` is always preserved as-is; the default is only
* filled in when a note omits `color` entirely (FlowNote.color is required).
*
* Free notes are also given a concrete `position` and `size` when missing. A
* free note without geometry is not draggable/resizable in the editor (you'd
* have to resize it first to give it a size) — UI-created notes always set both,
* so agent-created notes must too. Provided geometry is preserved untouched.
*/
export function validateFlowNotes(rawNotes: unknown, moduleIds?: Set<string>): FlowNote[] | null {
if (rawNotes == null) {
return null
}
if (!Array.isArray(rawNotes)) {
throw new Error('Flow notes must be an array')
}
const seenIds = new Set<string>()
// Column and running y-cursor for auto-placed free notes so consecutive ones
// stack below each other by their actual heights instead of overlapping. A
// preserved note (explicit geometry) sitting in this column also advances the
// cursor, so a later auto-placed note doesn't land on top of it.
const AUTO_STACK_X = -(MIN_NOTE_WIDTH + 100)
const AUTO_STACK_GAP = 24
let autoStackY = 0
return rawNotes.map((note, index) => {
if (!note || typeof note !== 'object' || Array.isArray(note)) {
throw new Error(`Invalid note at index ${index}: must be an object`)
}
const n = note as Record<string, unknown>
if (typeof n.id !== 'string' || !n.id) {
throw new Error(`Invalid note at index ${index}: id must be a non-empty string`)
}View on GitHub (pinned to e474e8803c)
Solutions
- Wrap the note object(s) in an array: notes: [{ id: 'n1', text: '...' }]
- Pass null or omit notes entirely if there are no notes to set
- Ensure the argument is a JSON array before calling the tool
Example fix
// before
notes: { id: 'n1', text: 'Review this' }
// after
notes: [{ id: 'n1', text: 'Review this' }] Defensive patterns
Strategy: type-guard
Validate before calling
if (notes != null && !Array.isArray(notes)) {
notes = [notes]; // or throw before calling the tool
} Type guard
function isFlowNoteArray(v: unknown): v is FlowNote[] {
return v == null || (Array.isArray(v) && v.every((n) => n !== null && typeof n === 'object' && !Array.isArray(n)));
} Try / catch
try {
const notes = validateFlowNotes(rawNotes, moduleIds);
} catch (e) {
if (e instanceof Error && e.message === 'Flow notes must be an array') {
// coerce to [rawNotes] and retry once
} else throw e;
} Prevention
- Always pass notes as a JSON array, even for a single note
- Use null/undefined (or omit the field) when there are no notes
- Validate payload shape with a schema (zod) before calling the tool
When it happens
Trigger: Calling patch_flow_json/set_flow_json with notes: { id: 'n1', text: 'hi' } (single object instead of array) or notes: 'some text'.
Common situations: An LLM agent emits a single note object instead of wrapping it in an array; a caller confuses notes with a map keyed by id; JSON was flattened by an intermediate serialization step.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid note at index ${index}: must be an object
- Invalid note at index ${index}: text must be a string
- Invalid note at index ${index}: id must be a non-empty strin
- Invalid note at index ${index}: duplicate note id "${n.id}"
- Invalid note at index ${index}: type must be "free" or "grou
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/22d1189e601be1e8.
Report an issue: GitHub.