{"record":{"id":"547c89bd83b208bf","repo":"FlowiseAI/Flowise","slug":"custom-function-must-have-a-predecessor","errorCode":null,"errorMessage":"Custom function must have a predecessor!","messagePattern":"Custom function must have a predecessor!","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/components/nodes/sequentialagents/CustomFunction/CustomFunction.ts","lineNumber":101,"sourceCode":"                        name: 'stateObj',\n                        description: \"Return as state object, ex: { foo: bar }. This will update the custom state 'foo' to 'bar'\"\n                    }\n                ],\n                default: 'aiMessage'\n            }\n        ]\n    }\n\n    async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> {\n        const functionName = nodeData.inputs?.functionName as string\n        const javascriptFunction = nodeData.inputs?.javascriptFunction as string\n        const functionInputVariablesRaw = nodeData.inputs?.functionInputVariables\n        const appDataSource = options.appDataSource as DataSource\n        const databaseEntities = options.databaseEntities as IDatabaseEntity\n        const sequentialNodes = nodeData.inputs?.sequentialNode as ISeqAgentNode[]\n        const returnValueAs = nodeData.inputs?.returnValueAs as string\n\n        if (!sequentialNodes || !sequentialNodes.length) throw new Error('Custom function must have a predecessor!')\n\n        const executeFunc = async (state: ISeqAgentsState) => {\n            const variables = await getVars(appDataSource, databaseEntities, nodeData, options)\n            const flow = {\n                chatflowId: options.chatflowid,\n                sessionId: options.sessionId,\n                chatId: options.chatId,\n                input,\n                state\n            }\n\n            let inputVars: ICommonObject = {}\n            if (functionInputVariablesRaw) {\n                try {\n                    inputVars =\n                        typeof functionInputVariablesRaw === 'object' ? functionInputVariablesRaw : JSON.parse(functionInputVariablesRaw)\n                } catch (exception) {\n                    throw new Error('Invalid JSON in the Custom Function Input Variables: ' + exception)","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/nodes/sequentialagents/CustomFunction/CustomFunction.ts#L83-L119","documentation":"Thrown at init() of the Custom Function sequential node when nodeData.inputs.sequentialNode is undefined or an empty array. The sequential-agent graph (LangGraph) requires every non-Start node to declare at least one predecessor so the edges can be wired; a Custom Function with no incoming sequential connection cannot be placed in the graph.","triggerScenarios":"The Custom Function node was dropped on the canvas but never linked from an Agent / Condition / LLMNode / ToolNode / CustomFunction / ExecuteFlow output; the visual edge exists but was not serialized into inputs.sequentialNode (stale saved chatflow); sequentialNode was set to an empty array by a corrupted import.","commonSituations":"Building a new sequential flow and forgetting the wire before save/preview; copying a node without copying its edges; loading an older chatflow whose schema predates the sequentialNode field.","solutions":["In the Flowise canvas, draw a connection from an upstream sequential node's output into this Custom Function's 'Sequential Node' input.","Save the chatflow again so the edge is serialized into inputs.sequentialNode.","Reopen the node and confirm a predecessor appears in the 'Sequential Node' parameter."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const seq = nodeData.inputs?.sequentialNode\nif (!Array.isArray(seq) || seq.length === 0) {\n  throw new Error('Custom Function must have a predecessor! Connect an upstream sequential node before init.')\n}","typeGuard":"const hasPredecessor = (n: INodeData): boolean =>\n  Array.isArray(n.inputs?.sequentialNode) && (n.inputs!.sequentialNode as any[]).length > 0","tryCatchPattern":null,"preventionTips":["Run a graph-wiring lint pass before save: every non-Start sequential node must have >=1 incoming edge.","After cloning a flow, re-verify all Sequential Node params are populated."],"tags":["sequential-agents","custom-function","graph-wiring","init"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}