windmill-labs/windmill · error · Error

the document must be a mapping (key: value)

Error message

the document must be a mapping (key: value)

What it means

validateShape in FlowYamlEditor.svelte guards against pasting YAML that is not a whole OpenFlow document. The parsed document must be a mapping (not a scalar or array); otherwise `value` assignment and downstream `flowStore.val.value.modules` access would crash the FlowEditor after a success toast.

Source

Thrown at frontend/src/lib/components/flows/header/FlowYamlEditor.svelte:40

	let code = $state('')
	let initialCode = $state('')
	let editor = $state(undefined) as SimpleEditor | undefined
	let hasChanges = $derived(code !== initialCode)

	function reload() {
		code = YAML.stringify(filteredContentForExport(flowStore.val))
		initialCode = code
		editor?.setCode(code)
	}

	/** `value` is assigned unconditionally below and `FlowEditor` dereferences
	 * `flowStore.val.value.modules`, so an OpenFlow document missing it takes the
	 * whole editor down mid-render — after the toast has already claimed success.
	 * Reject it up front instead. */
	function validateShape(parsed: unknown) {
		if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
			throw new Error('the document must be a mapping (key: value)')
		}
		const value = (parsed as Record<string, unknown>).value
		if (typeof value !== 'object' || value === null || Array.isArray(value)) {
			throw new Error("missing 'value' - paste a whole OpenFlow document, not just its value")
		}
		if (!Array.isArray((value as Record<string, unknown>).modules)) {
			throw new Error("'value.modules' must be a list")
		}
	}

	function validateGroups(groups: { start_id: string; end_id: string }[] | undefined) {
		if (!groups) return
		const seen = new Set<string>()
		for (const g of groups) {
			const key = `${g.start_id}:${g.end_id}`
			if (seen.has(key)) {
				throw new Error(`Duplicate group: '${g.start_id}' → '${g.end_id}'`)
			}

View on GitHub (pinned to e474e8803c)

Solutions

  1. Paste the complete OpenFlow document including the top-level `value` key with a `modules` array
  2. Wrap scalar/list YAML under a mapping, e.g. `value:\n modules: [...]`
  3. Use the flow's Export function to get a correctly shaped document and edit that

Example fix

// before
- id: a
  value: {}
// after
value:
  modules:
    - id: a
      value: {}
Defensive patterns

Strategy: validation

Validate before calling

const doc = YAML.parse(text)
if (typeof doc !== 'object' || doc === null || Array.isArray(doc)) throw new Error('Paste a whole OpenFlow mapping, not a list or scalar')
if (!doc.value || Array.isArray(doc.value) || !Array.isArray(doc.value.modules)) throw new Error("Missing value.modules")

Type guard

function isOpenFlowDoc(v: unknown): v is { value: { modules: unknown[] } } {
  return typeof v === 'object' && v !== null && !Array.isArray(v) &&
    typeof (v as any).value === 'object' && (v as any).value !== null &&
    Array.isArray((v as any).value.modules)
}

Try / catch

try { apply(text) } catch (e) { sendUserToast(e.message, true) }

Prevention

When it happens

Trigger: The user pastes YAML that parses to a scalar or a list (e.g. just the modules list, or a single key line) into the YAML editor and clicks apply; validateShape runs before storing and rejects it.

Common situations: Copying only the `value:` subtree instead of the full OpenFlow document; pasting a flow snippet from docs that is an array of steps; YAML with top-level sequence syntax (dashes).

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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