{"record":{"id":"e05188ec29c36cf9","repo":"jaegertracing/jaeger","slug":"invalid-span-id-q-w","errorCode":null,"errorMessage":"invalid span_id %q: %w","messagePattern":"invalid span_id %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/jaeger/internal/extension/jaegerquery/internal/mcptools/internal/handlers/get_span_details.go","lineNumber":156,"sourceCode":"\t\t\tlen(input.SpanIDs),\n\t\t\th.maxSpanDetailsPerRequest,\n\t\t)\n\t}\n\n\ttraceID, err := parseTraceID(input.TraceID)\n\tif err != nil {\n\t\treturn querysvc.GetTraceParams{}, nil, fmt.Errorf(\"invalid trace_id: %w\", err)\n\t}\n\n\t// Validate every span_id up front so a malformed value fails fast instead of\n\t// triggering a backend query that can never match a real span ID. Collect the\n\t// canonical lowercase hex form so the lookup set agrees with the ID the trace\n\t// iterator emits regardless of the request's casing.\n\tcanonicalSpanIDs := make([]string, 0, len(input.SpanIDs))\n\tfor _, spanIDStr := range input.SpanIDs {\n\t\tspanID, err := parseSpanID(spanIDStr)\n\t\tif err != nil {\n\t\t\treturn querysvc.GetTraceParams{}, nil, fmt.Errorf(\"invalid span_id %q: %w\", spanIDStr, err)\n\t\t}\n\t\tcanonicalSpanIDs = append(canonicalSpanIDs, spanID.String())\n\t}\n\n\treturn querysvc.GetTraceParams{\n\t\tTraceIDs: []tracestore.GetTraceParams{\n\t\t\t{TraceID: traceID},\n\t\t},\n\t\tRawTraces: false, // We want adjusted traces\n\t}, canonicalSpanIDs, nil\n}\n\n// buildSpanDetail constructs a SpanDetail from a ptrace.Span.\nfunc buildSpanDetail(pos jptrace.SpanIterPos, span ptrace.Span) types.SpanDetail {\n\t// Get service name from resource attributes\n\tserviceName := \"\"\n\tif svc, ok := pos.Resource.Resource().Attributes().Get(\"service.name\"); ok {\n\t\tserviceName = svc.Str()","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/jaegertracing/jaeger/blob/806f4447841ecdb60519f408b004a599d515f437/cmd/jaeger/internal/extension/jaegerquery/internal/mcptools/internal/handlers/get_span_details.go#L138-L174","documentation":"Each entry in input.SpanIDs is validated with parseSpanID before querying. A malformed span ID (wrong hex format or length) aborts the whole request with \"invalid span_id \\\"<value>\\\": <reason>\". The message quotes the offending value so the client can fix exactly that entry; validation happens up front to avoid a doomed backend query.","triggerScenarios":"Calling get_span_details with any SpanIDs element that parseSpanID rejects: non-hex characters, empty string, wrong length for pcommon.SpanID, or an ID containing separators/prefixes.","commonSituations":"Span IDs copied from spans/JSON attributes that were already hex-decoded or base64-encoded; mixing 8-byte span IDs from other instrumentation with the expected format; list built by concatenating IDs with commas instead of separate array elements.","solutions":["Fix the quoted span ID to be valid hex of the expected length.","Remove or correct empty/placeholder entries in the span_ids array.","Ensure IDs are passed as separate array elements, not a delimited string.","Decode from the correct representation: span IDs in Jaeger API/OTLP are hex strings, not raw bytes or base64."],"exampleFix":"// before\nSpanIDs: [\"abc\", \"7c4485\"+\"-01\"]\n// after\nSpanIDs: [\"bf39692569d65829\", \"7c44850100000000\"]","handlingStrategy":"validation","validationCode":"func validSpanID(s string) bool {\n\tif len(s) != 16 { return false } // pcommon.SpanID is 8 bytes\n\t_, err := hex.DecodeString(s)\n\treturn err == nil\n}\n// filter: spanIDs = slices.DeleteFunc(spanIDs, func(id string) bool { return !validSpanID(id) })","typeGuard":"func normalizeSpanID(s string) (string, bool) {\n\ts = strings.TrimPrefix(strings.TrimSpace(s), \"0x\")\n\tif _, err := hex.DecodeString(s); err != nil || len(s) == 0 { return \"\", false }\n\treturn strings.ToLower(s), true\n}","tryCatchPattern":"out, _, err := handler.Handle(ctx, req, input)\nif err != nil && strings.HasPrefix(err.Error(), \"invalid span_id\") {\n\tvar bad string\n\tfmt.Sscanf(err.Error(), \"invalid span_id %q\", &bad)\n\tinput.SpanIDs = slices.DeleteFunc(input.SpanIDs, func(id string) bool { return id == bad })\n\tout, _, err = handler.Handle(ctx, req, input)\n}","preventionTips":["Validate every span ID as hex before adding it to span_ids.","Pass IDs as separate array elements, never a delimited string.","Use hex span IDs exactly as returned by the Jaeger API, not decoded bytes.","Parse the quoted offending ID from the error to auto-clean the list."],"tags":["mcp","validation","span-id","jaeger"],"backgroundTag":"invalid-span-id-format","analyzedSha":"806f4447841ecdb60519f408b004a599d515f437","analyzedAt":"2026-09-01T02:39:22.140Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}