windmill-labs/windmill · error

Flow schema must be an object or null

Error message

Flow schema must be an object or null

What it means

validateFlowSchema enforces that the flow's input `schema`, when present, is a plain JSON object; null means 'no schema'. Arrays, strings, numbers, and booleans are rejected because Windmill flow input schemas must be JSON-Schema object documents. The check runs inside the copilot's editable-flow validator before the flow is written.

Source

Thrown at frontend/src/lib/components/copilot/chat/flow/editableFlowJson.ts:305

				.map(
					(t) =>
						`agent "${t.agentId}" tool "${t.toolId}" is named ${JSON.stringify(t.name)} - ${t.error}`
				)
				.join(
					'; '
				)}. The tool's "summary" is the name the agent calls it by: use underscores instead of spaces (e.g. "search_docs").`
		)
	}

	validateAiAgentProviders(parsedModules, ctx.aiProviders, ctx.aiProviderWarnings)

	return parsedModules
}

export function validateFlowSchema(rawSchema: unknown): Record<string, any> | null {
	if (rawSchema == null) return null
	if (typeof rawSchema !== 'object' || Array.isArray(rawSchema)) {
		throw new Error('Flow schema must be an object or null')
	}
	return rawSchema as Record<string, any>
}

function validateOptionalFlowModule(rawModule: unknown, fieldName: string): FlowModule | null {
	if (rawModule == null) return null

	const result = flowModuleSchema.safeParse(rawModule)
	if (!result.success) {
		const error = result.error.issues[0]
		throw new Error(`Invalid ${fieldName}: ${error?.message ?? 'unknown error'}`)
	}
	return result.data
}

export const EDITABLE_FLOW_STRUCTURAL_KEYS = [
	'modules',
	'schema',

View on GitHub (pinned to e474e8803c)

Solutions

  1. Pass a JSON object for the schema (e.g. {"type":"object","properties":{...}}) or null/omit it entirely.
  2. If the schema is a JSON string, JSON.parse it before passing.
  3. If properties were collected into an array, convert them to an object keyed by property name.

Example fix

// before
schema: '[{"name":"email","type":"string"}]'
// after
schema: {"type":"object","properties":{"email":{"type":"string"}}}
Defensive patterns

Strategy: type-guard

Validate before calling

function assertFlowSchema(s) {
  if (s == null) return null
  if (typeof s !== 'object' || Array.isArray(s))
    throw new TypeError('Flow schema must be a JSON object or null')
  return s
}

Type guard

function isFlowSchema(v) {
  return v === null || (typeof v === 'object' && !Array.isArray(v))
}

Try / catch

try {
  const schema = validateFlowSchema(rawSchema)
} catch (e) {
  if (String(e.message) === 'Flow schema must be an object or null') {
    // pass null or a parsed object instead
  } else throw e
}

Prevention

When it happens

Trigger: Calling flowTools/schema (or a flow patch that touches schema) with a value that is an array, a stringified JSON schema, or another non-object non-null value.

Common situations: An LLM emits the schema as an array of properties or as a JSON string; a user pastes a JSON Schema draft wrapped in quotes; code passes `[]` as a default.

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/156c1552d01db9f5. Report an issue: GitHub.