{"record":{"id":"6e4b79c81f2d6250","repo":"microsoft/semantic-kernel","slug":"processmapbuilder-may-not-target-another-processma","errorCode":null,"errorMessage":"ProcessMapBuilder may not target another ProcessMapBuilder.","messagePattern":"ProcessMapBuilder may not target another ProcessMapBuilder\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Experimental/Process.Core/ProcessStepEdgeBuilder.cs","lineNumber":125,"sourceCode":"    /// <summary>\n    /// Internally overridable implementation: Signals that the output of the source step should be sent to the specified target when the associated event fires.\n    /// </summary>\n    /// <param name=\"target\">The output target.</param>\n    /// <returns>A fresh builder instance for fluid definition</returns>\n    /// <exception cref=\"InvalidOperationException\"></exception>\n    /// <exception cref=\"ArgumentException\"></exception>\n    internal virtual ProcessStepEdgeBuilder SendEventTo_Internal(ProcessTargetBuilder target)\n    {\n        if (this.Target is not null)\n        {\n            throw new InvalidOperationException(\"An output target has already been set.\");\n        }\n\n        if (target is ProcessFunctionTargetBuilder functionTargetBuilder)\n        {\n            if (functionTargetBuilder.Step is ProcessMapBuilder && this.Source is ProcessMapBuilder)\n            {\n                throw new ArgumentException($\"{nameof(ProcessMapBuilder)} may not target another {nameof(ProcessMapBuilder)}.\", nameof(target));\n            }\n        }\n\n        this.Target = target;\n        this.Source.LinkTo(this.EventData.EventId, this);\n\n        return new ProcessStepEdgeBuilder(this.Source, this.EventData.EventId, this.EventData.EventName, this.EdgeGroupBuilder, this.Condition);\n    }\n\n    /// <summary>\n    /// Emit the SK step event as an external event with specific topic name\n    /// </summary>\n    /// <returns></returns>\n    public ProcessStepEdgeBuilder EmitExternalEvent(ProcessProxyBuilder proxyStep, string topicName)\n    {\n        // 1. Link sk event and topic\n        proxyStep.LinkTopicToStepEdgeInfo(topicName, this.Source, this.EventData);\n","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/dotnet/src/Experimental/Process.Core/ProcessStepEdgeBuilder.cs#L107-L143","documentation":"Thrown by SendEventTo_Internal when the source step is a ProcessMapBuilder and the resolved target is also a ProcessMapBuilder. The framework explicitly forbids a map step from directly targeting another map step, so a ProcessMapBuilder cannot be wired into another ProcessMapBuilder.","triggerScenarios":"Calling SendEventTo with a function target whose Step is a ProcessMapBuilder, from an edge whose Source is itself a ProcessMapBuilder (map-to-map wiring).","commonSituations":"Composing nested map operations and trying to chain one map directly into another; modeling pipelines where two ProcessMapBuilder steps are adjacent without an intermediate step.","solutions":["Insert a non-map intermediate step (a regular KernelProcessStep) between the two ProcessMapBuilder steps so the edge is map -> step -> map.","Reconsider whether the two maps can be merged into a single ProcessMapBuilder.","If the target map was meant to consume the source map's output, route via a proxy/relay step that forwards the message."],"exampleFix":"// before: map -> map (throws)\nmapA.OnEvent(\"Out\").SendEventTo(mapB.GetTarget());\n\n// after: map -> relay step -> map\nmapA.OnEvent(\"Out\").SendEventTo(relayStep.GetTarget());\nrelayStep.OnEvent(\"Out\").SendEventTo(mapB.GetTarget());","handlingStrategy":"validation","validationCode":"if (source is ProcessMapBuilder && target.Step is ProcessMapBuilder)\n    throw new InvalidOperationException(\"Insert a non-map step between two ProcessMapBuilder steps.\");","typeGuard":"static bool IsMapToMap(ProcessStepBuilder src, ProcessFunctionTargetBuilder tgt) => src is ProcessMapBuilder && tgt.Step is ProcessMapBuilder;","tryCatchPattern":"try { edge.SendEventTo(mapTarget); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"may not target another\"))\n{ /* route through an intermediate non-map step */ }","preventionTips":["Never wire two ProcessMapBuilder steps directly; always interpose a relay step.","Document map-step adjacency rules for workflow authors.","Add a unit test asserting map->map is rejected to lock the contract."],"tags":["semantic-kernel","process","map","edge"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}