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
- Pass a JSON object for the schema (e.g. {"type":"object","properties":{...}}) or null/omit it entirely.
- If the schema is a JSON string, JSON.parse it before passing.
- 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
- JSON.parse stringified schemas before passing them
- Never pass property lists as arrays; key them by property name
- Treat 'no schema' as null or undefined, not []
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
- Missing required arguments: ${required.join(", ")}. Use -d '
- Flow JSON must be an object
- Couldn't create schema validator for script requiring schema
- {webhook_key} must be a URL string, got {kind}
- Field properties should be an object
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/156c1552d01db9f5.
Report an issue: GitHub.