{"record":{"id":"156c1552d01db9f5","repo":"windmill-labs/windmill","slug":"flow-schema-must-be-an-object-or-null","errorCode":null,"errorMessage":"Flow schema must be an object or null","messagePattern":"Flow schema must be an object or null","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/flow/editableFlowJson.ts","lineNumber":305,"sourceCode":"\t\t\t\t.map(\n\t\t\t\t\t(t) =>\n\t\t\t\t\t\t`agent \"${t.agentId}\" tool \"${t.toolId}\" is named ${JSON.stringify(t.name)} - ${t.error}`\n\t\t\t\t)\n\t\t\t\t.join(\n\t\t\t\t\t'; '\n\t\t\t\t)}. The tool's \"summary\" is the name the agent calls it by: use underscores instead of spaces (e.g. \"search_docs\").`\n\t\t)\n\t}\n\n\tvalidateAiAgentProviders(parsedModules, ctx.aiProviders, ctx.aiProviderWarnings)\n\n\treturn parsedModules\n}\n\nexport function validateFlowSchema(rawSchema: unknown): Record<string, any> | null {\n\tif (rawSchema == null) return null\n\tif (typeof rawSchema !== 'object' || Array.isArray(rawSchema)) {\n\t\tthrow new Error('Flow schema must be an object or null')\n\t}\n\treturn rawSchema as Record<string, any>\n}\n\nfunction validateOptionalFlowModule(rawModule: unknown, fieldName: string): FlowModule | null {\n\tif (rawModule == null) return null\n\n\tconst result = flowModuleSchema.safeParse(rawModule)\n\tif (!result.success) {\n\t\tconst error = result.error.issues[0]\n\t\tthrow new Error(`Invalid ${fieldName}: ${error?.message ?? 'unknown error'}`)\n\t}\n\treturn result.data\n}\n\nexport const EDITABLE_FLOW_STRUCTURAL_KEYS = [\n\t'modules',\n\t'schema',","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/flow/editableFlowJson.ts#L287-L323","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nschema: '[{\"name\":\"email\",\"type\":\"string\"}]'\n// after\nschema: {\"type\":\"object\",\"properties\":{\"email\":{\"type\":\"string\"}}}","handlingStrategy":"type-guard","validationCode":"function assertFlowSchema(s) {\n  if (s == null) return null\n  if (typeof s !== 'object' || Array.isArray(s))\n    throw new TypeError('Flow schema must be a JSON object or null')\n  return s\n}","typeGuard":"function isFlowSchema(v) {\n  return v === null || (typeof v === 'object' && !Array.isArray(v))\n}","tryCatchPattern":"try {\n  const schema = validateFlowSchema(rawSchema)\n} catch (e) {\n  if (String(e.message) === 'Flow schema must be an object or null') {\n    // pass null or a parsed object instead\n  } else throw e\n}","preventionTips":["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 []"],"tags":["validation","json-schema","types"],"backgroundTag":"schema-validation-failed","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}