{"record":{"id":"28f1d2afa7aa94cc","repo":"BabylonJS/Babylon.js","slug":"block-connection-outputblock-does-not-have-an-c","errorCode":null,"errorMessage":"Block ${connection.outputBlock} does not have an connection point named ${connection.outputConnectionPoint}","messagePattern":"Block (.+?) does not have an connection point named (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/smartFilters/src/serialization/smartFilterDeserializer.ts","lineNumber":99,"sourceCode":"        });\r\n        await Promise.all(blockDeserializationWork);\r\n\r\n        // If any block definitions could not be deserialized, throw an error\r\n        if (blockDefinitionsWhichCouldNotBeDeserialized.length > 0) {\r\n            throw new Error(`Could not deserialize the following block definitions: ${blockDefinitionsWhichCouldNotBeDeserialized.join(\", \")}`);\r\n        }\r\n\r\n        // Deserialize the connections\r\n        serializedSmartFilter.connections.forEach((connection: ISerializedConnectionV1) => {\r\n            // Find the source block and its connection point's connectTo function\r\n            const sourceBlock = typeof connection.outputBlock === \"string\" ? blockNameMap.get(connection.outputBlock) : blockIdMap.get(connection.outputBlock);\r\n\r\n            if (!sourceBlock) {\r\n                throw new Error(`Source block ${connection.outputBlock} not found`);\r\n            }\r\n            const sourceConnectionPoint = sourceBlock.outputs.find((output) => output.name === connection.outputConnectionPoint);\r\n            if (!sourceConnectionPoint || typeof sourceConnectionPoint.connectTo !== \"function\") {\r\n                throw new Error(`Block ${connection.outputBlock} does not have an connection point named ${connection.outputConnectionPoint}`);\r\n            }\r\n            const sourceConnectToFunction = sourceConnectionPoint.connectTo.bind(sourceConnectionPoint);\r\n\r\n            // Find the target block and its connection point\r\n            const targetBlock = typeof connection.inputBlock === \"string\" ? blockNameMap.get(connection.inputBlock) : blockIdMap.get(connection.inputBlock);\r\n            if (!targetBlock) {\r\n                throw new Error(`Target block ${connection.inputBlock} not found`);\r\n            }\r\n\r\n            const targetConnectionPoint = targetBlock.inputs.find((input) => input.name === connection.inputConnectionPoint);\r\n            if (!targetConnectionPoint || typeof targetConnectionPoint !== \"object\") {\r\n                throw new Error(`Block ${connection.inputBlock} does not have a connection point named ${connection.inputConnectionPoint}`);\r\n            }\r\n\r\n            // Create the connection\r\n            sourceConnectToFunction.call(sourceBlock, targetConnectionPoint);\r\n        });\r\n\r","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/smartFilters/src/serialization/smartFilterDeserializer.ts#L81-L117","documentation":"The source block was found, but none of its output connection points matches connection.outputConnectionPoint, or that output has no connectTo function. Connection endpoints are validated by name during deserialization, so a connection pointing at a nonexistent output makes the serialized graph invalid.","triggerScenarios":"connection.outputConnectionPoint names an output the block does not expose — renamed connection points between versions, a typo in hand-edited JSON, or a connection serialized from a block of a different type that has differently named outputs.","commonSituations":"Upgrading block implementations whose output names changed, hand-editing filter JSON, copying connection entries between blocks of different types, custom blocks whose outputs were refactored.","solutions":["Correct outputConnectionPoint in the JSON to match the block's actual output name (inspect the block class's outputs).","Re-export the filter from the current editor/tooling version so connection point names are regenerated.","Update custom block code to keep the historical output name, or migrate the serialized connections.","Confirm the block type resolved is the intended one — a wrong blockType lookup can yield a block with different outputs.","Add a pre-deserialization validator comparing connection endpoints against each block's declared inputs/outputs."],"exampleFix":"// before\n{ \"outputBlock\": \"Blur\", \"outputConnectionPoint\": \"output\", ... } // actual name \"out\"\n// after\n{ \"outputBlock\": \"Blur\", \"outputConnectionPoint\": \"out\", ... }","handlingStrategy":"validation","validationCode":"function validateSourceConnectionPoints(serialized, blockRegistry) {\n  for (const c of serialized.connections) {\n    const block = serialized.blocks.find((b) => b.name === c.outputBlock || b.uniqueId === c.outputBlock);\n    if (block && !blockRegistry.getOutputs(block).includes(c.outputConnectionPoint)) {\n      throw new Error(`Block ${c.outputBlock} has no output '${c.outputConnectionPoint}'`);\n    }\n  }\n}","typeGuard":"function hasOutput(block, name) {\n  return block?.outputs?.some((o) => o.name === name) ?? false;\n}","tryCatchPattern":"try {\n  const filter = await SmartFilterDeserializer.DeserializeAsync(runtime, container, json);\n} catch (e) {\n  const m = e.message.match(/Block (.+) does not have an connection point named (.+)/);\n  if (m) throw new Error(`Fix output endpoint: block '${m[1]}' has no output '${m[2]}'`);\n  throw e;\n}","preventionTips":["Check block class outputs for exact connection point names after refactors.","Re-export filters when block implementations change output names.","Write migrations renaming endpoints across versions.","Never copy connection entries between different block types.","Add endpoint validation as a pre-deserialization step in tooling."],"tags":["smart-filters","deserialization","graph-integrity","connection-points"],"backgroundTag":"dangling-reference-in-graph","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}