temporalio/temporal · error

no spans to export

Error message

no spans to export

What it means

memExporterClient.Write dumps recorded OTel spans to a JSON file in the exporter's output directory. If no spans were collected, there is nothing to export, so it returns this error instead of writing an empty file. It is a guard against silently producing meaningless telemetry snapshots in tests.

Source

Thrown at common/testing/testtelemetry/exporter.go:89

}

func (c *memExporterClient) UploadTraces(
	ctx context.Context,
	protoSpans []*tracepb.ResourceSpans,
) error {
	c.spansLock.Lock()
	defer c.spansLock.Unlock()

	c.spans = append(c.spans, protoSpans...)
	return nil
}

func (c *memExporterClient) Write(filename string) (string, error) {
	c.spansLock.Lock()
	defer c.spansLock.Unlock()

	if len(c.spans) == 0 {
		return "", errors.New("no spans to export")
	}

	if err := os.MkdirAll(c.outDir, 0o755); err != nil {
		return "", err
	}

	filePath := filepath.Join(c.outDir, filename)
	file, err := os.Create(filePath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	marshaler := &ptrace.JSONMarshaler{}
	unmarshaler := &ptrace.ProtoUnmarshaler{}

	// Write each ResourceSpan as a separate line.
	for _, resourceSpan := range c.spans {

View on GitHub (pinned to bde624efd1)

Solutions

  1. Ensure the traced code path runs before calling Write (check the code under test actually emits spans)
  2. Confirm you are calling Write on the same memExporterClient that the tracer provider registered
  3. If exporting zero spans is legitimately expected, check len(c.spans) yourself before calling Write or treat the error as a no-op

Example fix

// before
_, err := client.Write(filename) // may fail with no spans
// after
client.spansLock.Lock()
hasSpans := len(client.spans) > 0
client.spansLock.Unlock()
if hasSpans {
    _, err := client.Write(filename)
    require.NoError(t, err)
}
Defensive patterns

Strategy: validation

Validate before calling

if len(client.spans) == 0 {
    t.Skip("no spans recorded; skipping telemetry export assertion")
}

Try / catch

path, err := client.Write(filename)
if err != nil && strings.Contains(err.Error(), "no spans to export") {
    // verify traced code ran; do not treat as fatal if zero spans is expected
}

Prevention

When it happens

Trigger: Calling Write on the in-memory telemetry exporter before any span was recorded (c.spans is empty).

Common situations: Test asserts telemetry before the instrumented code ran; wrong exporter instance consulted (spans recorded on a different client); the traced operation failed before emitting spans.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/334038e13633ff91. Report an issue: GitHub.