{"record":{"id":"829e10d6a20d7cc6","repo":"microsoft/semantic-kernel","slug":"a-target-and-source-must-be-specified-before-build","errorCode":null,"errorMessage":"A target and Source must be specified before building the edge.","messagePattern":"A target and Source must be specified before building the edge\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Experimental/Process.Core/ProcessStepEdgeBuilder.cs","lineNumber":69,"sourceCode":"        Verify.NotNull(source, nameof(source));\n        Verify.NotNullOrWhiteSpace(eventId, nameof(eventId));\n\n        this.Source = source;\n        this.EventData = new() { EventId = eventId, EventName = eventName };\n        this.EdgeGroupBuilder = edgeGroupBuilder;\n        this.Condition = condition;\n    }\n\n    /// <summary>\n    /// Builds the edge.\n    /// </summary>\n    internal KernelProcessEdge Build(ProcessBuilder? processBuilder = null)\n    {\n        Verify.NotNull(this.Source?.Id);\n\n        if (this.Target is null || this.Source?.Id is null)\n        {\n            throw new InvalidOperationException(\"A target and Source must be specified before building the edge.\");\n        }\n\n        if (this.Target is ProcessFunctionTargetBuilder functionTargetBuilder)\n        {\n            if (this.EdgeGroupBuilder is not null && this.Target is ProcessStepTargetBuilder stepTargetBuilder)\n            {\n                var messageSources = this.EdgeGroupBuilder.MessageSources.Select(e => new KernelProcessMessageSource(e.MessageType, e.Source.Id)).ToList();\n                var edgeGroup = new KernelProcessEdgeGroup(this.EdgeGroupBuilder.GroupId, messageSources, stepTargetBuilder.InputMapping);\n                functionTargetBuilder.Step.RegisterGroupInputMapping(edgeGroup);\n            }\n        }\n\n        return new KernelProcessEdge(this.Source.Id, this.Target.Build(processBuilder), groupId: this.EdgeGroupBuilder?.GroupId, this.Condition, this.VariableUpdate);\n    }\n\n    /// <summary>\n    /// Signals that the output of the source step should be sent to the specified target when the associated event fires.\n    /// </summary>","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/dotnet/src/Experimental/Process.Core/ProcessStepEdgeBuilder.cs#L51-L87","documentation":"Thrown by ProcessStepEdgeBuilder.Build when an edge is being materialized but either the Target was never set or the Source step has no Id. Build requires both a non-null Target and a non-null Source.Id to construct a KernelProcessEdge.","triggerScenarios":"Calling Build() on an edge builder whose SendEventTo/ConfigureTarget was never invoked, or whose source ProcessStepBuilder has a null Id (not yet named/registered). Also reachable if framework code calls Build on a freshly created edge before linking.","commonSituations":"Building a process programmatically and forgetting to chain .SendEventTo(...); creating an edge manually for testing without assigning a target; or a step whose Id assignment was skipped.","solutions":["Complete the edge definition by calling SendEventTo (or an equivalent target setter) before Build runs.","Ensure the source step has a non-null Id by naming/registering it in the ProcessBuilder before building edges.","If you instantiate ProcessStepEdgeBuilder directly, set both Source.Id and Target before invoking Build.","Audit the fluent chain to confirm no .OnEvent(...).SendEventTo(...) branch was left without a terminal SendEventTo."],"exampleFix":"// before: edge has no target\nstep.OnEvent(\"Done\")\n//   .SendEventTo(...) missing\n\n// after: terminate with a target\nstep.OnEvent(\"Done\")\n   .SendEventTo(otherStep);\n","handlingStrategy":"validation","validationCode":"if (edge.Target is null || string.IsNullOrEmpty(edge.Source?.Id))\n    throw new InvalidOperationException(\"Edge is incomplete; set Target and Source.Id first.\");","typeGuard":"static bool IsEdgeComplete(ProcessStepEdgeBuilder e) => e.Target is not null && !string.IsNullOrEmpty(e.Source?.Id);","tryCatchPattern":"try { var kernelEdge = edgeBuilder.Build(processBuilder); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"target and Source\"))\n{ /* ensure SendEventTo was called and Source.Id is set */ }","preventionTips":["Always terminate an OnEvent chain with SendEventTo before building.","Register/name every source step so its Id is non-null.","Add an integration test that builds the full process to catch dangling edges early."],"tags":["semantic-kernel","process","edge","builder"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}