windmill-labs/windmill · error · Error

Invalid note at index ${index}: color must be one of ${[...A

Error message

Invalid note at index ${index}: color must be one of ${[...ALLOWED_NOTE_COLORS].join(', ')}

What it means

Note colors are restricted to the NoteColor palette (yellow, blue, green, purple, pink, orange, red, cyan, lime, gray) because the renderer styles notes by these exact names. A non-string color or a string outside the palette throws this error in validateFlowNotes.

Source

Thrown at frontend/src/lib/components/copilot/chat/flow/helperUtils.ts:188

		}
		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`)
		}
		if (seenIds.has(n.id)) {
			throw new Error(`Invalid note at index ${index}: duplicate note id "${n.id}"`)
		}
		seenIds.add(n.id)
		if (typeof n.text !== 'string') {
			throw new Error(`Invalid note at index ${index}: text must be a string`)
		}
		const type = n.type ?? 'free'
		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) {

View on GitHub (pinned to e474e8803c)

Solutions

  1. Use one of the palette names exactly: yellow, blue, green, purple, pink, orange, red, cyan, lime, gray
  2. Omit color (undefined/null) to let the validator fill in the default note color
  3. Map hex/CSS colors to the nearest palette name before sending

Example fix

// before
notes: [{ id: 'n1', text: 'x', color: '#FF0000' }]
// after
notes: [{ id: 'n1', text: 'x', color: 'red' }]
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = ['yellow','blue','green','purple','pink','orange','red','cyan','lime','gray'];
notes.forEach((n, i) => {
  if (n.color != null && !ALLOWED.includes(n.color)) throw new Error(`notes[${i}].color "${n.color}" not in palette`);
});

Type guard

function isNoteColor(c: unknown): c is NoteColor {
  return typeof c === 'string' && (Object.values(NoteColor) as string[]).includes(c);
}

Try / catch

try {
  validateFlowNotes(rawNotes, moduleIds);
} catch (e) {
  if (e instanceof Error && e.message.includes('color must be one of')) {
    // retry with color omitted to accept the default
  } else throw e;
}

Prevention

When it happens

Trigger: notes: [{ id: 'n1', text: 'x', color: '#fff3cd' }] or color: 'amber' or color: 1 passed to patch_flow_json/set_flow_json.

Common situations: An LLM agent outputs hex codes or CSS color names outside the palette; a numeric enum index was passed; colors were copied from another design system's vocabulary.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/00d73a230bffd16d. Report an issue: GitHub.