{"record":{"id":"478c9c60f95b31f1","repo":"iOfficeAI/OfficeCLI","slug":"sequence-diagram-has-no-participants","errorCode":null,"errorMessage":"sequence diagram has no participants.","messagePattern":"sequence diagram has no participants\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/Diagram/SequenceLayout.cs","lineNumber":101,"sourceCode":"                {\n                    From = mm.Groups[1].Value,\n                    To = mm.Groups[3].Value,\n                    Label = mm.Groups[4].Value.Trim(),\n                    Dashed = op.StartsWith(\"--\"),\n                    Arrow = op.Contains('>') || op.Contains('x') || op.Contains(')'),\n                });\n            }\n        }\n        return d;\n    }\n\n    public static LaidOutGraph Layout(SequenceDiagram d)\n    {\n        const double boxH = 1.1, top = 0.8, hGap = 1.4, row = 1.15;\n        var order = d.Participants;\n        var lo = new LaidOutGraph { FontScale = 1.0 };\n        if (order.Count == 0)\n            throw new ArgumentException(\"sequence diagram has no participants.\");\n\n        // participant x positions (left, width) + lifeline centre\n        var left = new Dictionary<string, double>();\n        var width = new Dictionary<string, double>();\n        var cxOf = new Dictionary<string, double>();\n        double cur = 0.8;\n        foreach (var p in order)\n        {\n            double w = Math.Max(2.4, TextWidth(p.Label) + 1.0);\n            left[p.Id] = cur; width[p.Id] = w; cxOf[p.Id] = cur + w / 2;\n            cur += w + hGap;\n        }\n        double bodyTop = top + boxH + 0.9;\n        double bottom = bodyTop + Math.Max(1, d.Messages.Count) * row + 0.6;\n        lo.SlideWidthCm = Math.Max(cur - hGap + 0.8, 12.0);\n        lo.SlideHeightCm = bottom + 0.8;\n\n        // participant boxes + lifelines","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/Diagram/SequenceLayout.cs#L83-L119","documentation":"SequenceLayout.Layout computes participant columns and lifelines from d.Participants; with an empty list there is nothing to lay out, so it throws ArgumentException. This is a contract violation by the caller — a SequenceDiagram must declare at least one participant before layout.","triggerScenarios":"A caller built a SequenceDiagram (e.g. from parsed text or an API) and added messages without ever adding a participant, then passed it to SequenceLayout.Layout. order.Count == 0 trips the guard before any positioning math.","commonSituations":"Parsing a sequence block that has only messages with inline actor syntax but the parser didn't synthesize participants; an empty/whitespace sequence diagram body; a programmatic builder that forgot AddParticipant.","solutions":["Ensure at least one participant is added to the SequenceDiagram before calling Layout.","If parsing user input, synthesize participants from message sender/receiver when none are declared explicitly.","Validate Participants.Count > 0 before invoking Layout and emit a clear upstream error."],"exampleFix":"// before\nvar d = new SequenceDiagram();\nd.Messages.Add(new Msg(\"A\", \"B\", \"hi\"));\nvar laid = SequenceLayout.Layout(d); // throws — no participants\n\n// after\nvar d = new SequenceDiagram();\nd.Participants.Add(new Participant(\"A\", \"Alice\"));\nd.Participants.Add(new Participant(\"B\", \"Bob\"));\nd.Messages.Add(new Msg(\"A\", \"B\", \"hi\"));\nvar laid = SequenceLayout.Layout(d);","handlingStrategy":"validation","validationCode":"if (diagram.Participants == null || diagram.Participants.Count == 0)\n    throw new ArgumentException(\"Cannot lay out a sequence diagram with no participants; add participants or synthesize them from message senders/receivers.\");","typeGuard":"static bool IsLayableSequence(SequenceDiagram d)\n    => d != null && d.Participants is { Count: > 0 };","tryCatchPattern":"try { laid = SequenceLayout.Layout(d); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"no participants\", StringComparison.Ordinal))\n{\n    // synthesize participants from messages, then retry\n    foreach (var m in d.Messages) { EnsureParticipant(d, m.From); EnsureParticipant(d, m.To); }\n    laid = SequenceLayout.Layout(d);\n}","preventionTips":["Always add at least one participant before constructing messages programmatically.","When parsing, synthesize participants from message endpoints if none are declared.","Guard Participants.Count > 0 before calling Layout."],"tags":["sequence-diagram","validation","precondition","layout"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}