{"record":{"id":"0104f3d9bc271a61","repo":"mastra-ai/mastra","slug":"spanconverter-not-initialized-correctly","errorCode":null,"errorMessage":"SpanConverter not initialized correctly","messagePattern":"SpanConverter not initialized correctly","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"observability/otel-exporter/src/span-converter.ts","lineNumber":97,"sourceCode":"\n      this.resource = resource;\n      this.scope = {\n        name: this.params.packageName,\n        version: packageVersion,\n      };\n    })();\n\n    return this.initPromise;\n  }\n\n  /**\n   * Convert a Mastra Span to an OpenTelemetry ReadableSpan\n   */\n  async convertSpan(span: AnyExportedSpan): Promise<ReadableSpan> {\n    await this.initIfNeeded();\n\n    if (!this.resource || !this.scope) {\n      throw new Error('SpanConverter not initialized correctly');\n    }\n\n    // --- Core fields derived from Mastra span ---\n    const name = getSpanName(span);\n    const kind = getSpanKind(span.type);\n    const attributes = getAttributes(span);\n\n    // Add metadata as custom attributes (not gen_ai specific)\n    if (span.metadata) {\n      for (const [k, v] of Object.entries(span.metadata)) {\n        if (v === null || v === undefined) {\n          continue;\n        }\n        attributes[`mastra.metadata.${k}`] = typeof v === 'object' ? JSON.stringify(v) : v;\n      }\n    }\n\n    // Add tags for root spans (only root spans can have tags)","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/observability/otel-exporter/src/span-converter.ts#L79-L115","documentation":"SpanConverter lazily initializes its OpenTelemetry Resource and scope (instrumentation scope) on first use via initIfNeeded(), then converts Mastra exported spans into OTLP ReadableSpans. If resource or scope is still undefined after initIfNeeded, its internal state is inconsistent and it throws rather than emitting malformed telemetry. This indicates an SDK/tracer-provider setup problem, not bad span data.","triggerScenarios":"Calling convertSpan (directly or via otelSpan/readableSpan/result/llmResult/toolResult/rootResult helpers) when SpanConverter.initIfNeeded failed to set this.resource/this.scope — e.g. no OpenTelemetry tracer provider/SDK registered, init awaited a promise that resolved without setup, or the converter was constructed in an environment where OTel resource detection returned nothing.","commonSituations":"Exporting spans in serverless/edge runtimes without @opentelemetry/sdk-trace-base initialized; forgetting to configure the observability OTEL provider before spans flush; custom exporter instantiating SpanConverter directly instead of through the configured exporter; race where export runs before init completes.","solutions":["Ensure the OTEL exporter (and its tracer provider) is fully configured in Mastra observability options before spans are exported.","If using SpanConverter directly, call await converter.initIfNeeded() yourself and verify resource/scope are set before converting.","Check that @opentelemetry/sdk-trace-base/NodeSDK is initialized in the process (or a valid Resource is provided); missing SDK init is the usual cause.","Upgrade @mastra/observability + otel-exporter packages together to fix known init-race bugs."],"exampleFix":"// before: converting before provider init\nconst converter = new SpanConverter();\nconst rs = await converter.convertSpan(span);\n// after: explicit init and guard\nconst converter = new SpanConverter();\nawait converter.initIfNeeded();\nif (!isSpanConverterReady(converter)) throw new Error('Initialize OTel SDK before exporting spans');\nconst rs = await converter.convertSpan(span);","handlingStrategy":"type-guard","validationCode":"import { trace } from '@opentelemetry/api';\nif (!trace.getTracerProvider()) {\n  throw new Error('OpenTelemetry SDK not initialized; set up NodeSDK before exporting Mastra spans');\n}","typeGuard":"function isSpanConverterReady(c: object): boolean {\n  return 'resource' in c && 'scope' in c && !!(c as any).resource && !!(c as any).scope;\n}","tryCatchPattern":"try {\n  const readable = await converter.convertSpan(span);\n} catch (err) {\n  if (String(err.message) === 'SpanConverter not initialized correctly') {\n    console.error('OTel provider/resource missing; initialize the observability exporter before spans flush');\n    return; // or re-export after init\n  }\n  throw err;\n}","preventionTips":["Initialize the OTEL exporter/NodeSDK before any agent or workflow runs.","Let Mastra's configured exporter own SpanConverter lifecycle instead of instantiating it directly.","In serverless environments, verify resource detection yields a valid Resource.","Keep @mastra/observability and otel-exporter versions in lockstep."],"tags":["opentelemetry","initialization","tracing","lifecycle"],"backgroundTag":"not-initialized","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}