{"record":{"id":"e7e156395e568883","repo":"microsoft/aspire","slug":"duplicate-span-id-span-spanid-detected","errorCode":null,"errorMessage":"Duplicate span id '{span.SpanId}' detected.","messagePattern":"Duplicate span id '(.+?)' detected\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Dashboard/Otlp/Model/OtlpTrace.cs","lineNumber":44,"sourceCode":"    public int CalculateDepth(OtlpSpan span)\n    {\n        var depth = 0;\n        var currentSpan = span;\n        while (currentSpan != null)\n        {\n            depth++;\n            currentSpan = currentSpan.GetParentSpan();\n        }\n        return depth;\n    }\n\n    public int CalculateMaxDepth() => Spans.Max(CalculateDepth);\n\n    public void AddSpan(OtlpSpan span, bool skipLastUpdatedDate = false)\n    {\n        if (Spans.Contains(span.SpanId))\n        {\n            throw new InvalidOperationException($\"Duplicate span id '{span.SpanId}' detected.\");\n        }\n\n        var insertIndex = 0;\n        for (var i = Spans.Count - 1; i >= 0; i--)\n        {\n            if (span.StartTime > Spans[i].StartTime)\n            {\n                insertIndex = i + 1;\n                break;\n            }\n        }\n        Spans.Insert(insertIndex, span);\n\n        if (HasCircularReference(span))\n        {\n            Spans.Remove(span);\n            throw new InvalidOperationException($\"Circular loop detected for span '{span.SpanId}' with parent '{span.ParentSpanId}'.\");\n        }","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Dashboard/Otlp/Model/OtlpTrace.cs#L26-L62","documentation":"OtlpTrace.AddSpan enforces that each span id appears at most once within a trace. Since spans are kept in a list keyed/checked by SpanId, inserting a duplicate would corrupt the trace structure (double-counted nodes, broken depth/duration calculations). AddSpan throws this InvalidOperationException when the incoming span's SpanId already exists in Spans.","triggerScenarios":"AddSpan throws when Spans.Contains(span.SpanId) is true. Happens while materializing or adding OTLP spans (Clone, MaterializeTraces, filter paths) when the same span is delivered twice, e.g. duplicate exports from a retrying exporter or the same batch processed twice.","commonSituations":"OTLP exporter retries re-sending a batch after a timeout, producing duplicate span ids on the server; a collector delivering overlapping batches; test code calling AddSpan twice with the same span; replay of stored telemetry without deduplication.","solutions":["Deduplicate spans before export/at the collector so each SpanId is sent once per trace.","On the ingestion side, check trace.Spans for the id before calling AddSpan, or skip spans already present.","Investigate exporter retry configuration: enable idempotent delivery or reduce aggressive retries that resend identical batches."],"exampleFix":"// before\ntrace.AddSpan(span);\n// after\nif (!trace.Spans.Contains(span.SpanId))\n{\n    trace.AddSpan(span);\n}","handlingStrategy":"validation","validationCode":"// check before inserting\nif (trace.Spans.Any(s => s.SpanId == span.SpanId)) return; // skip duplicate","typeGuard":null,"tryCatchPattern":"try\n{\n    trace.AddSpan(span);\n}\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"Duplicate span id\"))\n{\n    logger.LogWarning(ex, \"Ignoring duplicate span {SpanId}.\", span.SpanId);\n}","preventionTips":["Configure exporters with deduplication/idempotent delivery to avoid resending batches.","Check collector pipelines for fan-out paths that deliver the same batch twice.","In tests, build each trace from spans with unique ids."],"tags":["opentelemetry","traces","duplicate","span","otlp"],"backgroundTag":"duplicate-record-detected","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}