JuliusBrussee/caveman · error

otlp decode

Error message

otlp decode: %w

What it means

parseOTLP wraps any json.Unmarshal failure of an OTLP/JSON trace payload with the "otlp decode: " prefix and returns no rows. The library throws it because the payload bytes are not valid JSON or do not match the expected otlpPayload structure (resourceSpans/scopeSpans/spans hierarchy). It guarantees callers get an error instead of silently decoding a partial or empty result.

Solutions

  1. Validate the payload is complete JSON before calling Parse (e.g. json.Valid(data)).
  2. Confirm the exporter emits OTLP/JSON, not OTLP/protobuf; convert or request JSON format.
  3. Log a snippet of the failing bytes around the JSON error offset to spot truncation or encoding issues.
  4. Ensure the source encodes fields with types matching the OTLP/JSON spec (hex string IDs, string attributes).

Example fix

// before
rows, err := Parse(body) // "otlp decode: unexpected end of JSON input"
// after
if !json.Valid(body) {
    return fmt.Errorf("payload is not valid JSON (len=%d)", len(body))
}
rows, err := Parse(body)
Defensive patterns

Strategy: validation

Validate before calling

if len(data) == 0 || !json.Valid(data) {
    return fmt.Errorf("otlp payload is not valid JSON (len=%d)", len(data))
}

Try / catch

rows, err := Parse(data)
if err != nil {
    if strings.HasPrefix(err.Error(), "otlp decode:") {
        return fmt.Errorf("invalid OTLP/JSON payload: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Parse/parseOTLP with bytes that are not valid JSON, truncated payloads, wrong content type (e.g. protobuf OTLP binary passed where OTLP/JSON is expected), or JSON with incompatible field types (e.g. traceId as number instead of string).

Common situations: Fetching traces from a collector endpoint that emits protobuf instead of JSON; reading a truncated or corrupted export file; ingesting output of a tool that logs non-JSON lines; schema drift after an OTLP version change (renamed or restructured fields).

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/cd5b916502fc1a70. Report an issue: GitHub.

Appendix: source

Thrown at shared/platform/importers/otlp.go:89

}

type otlpEvent struct {
	Name         string   `json:"name"`
	TimeUnixNano string   `json:"timeUnixNano"`
	Attributes   []otlpKV `json:"attributes"`
}

type otlpStatus struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

// parseOTLP decodes an OTLP/JSON trace payload and maps GenAI semantic
// conventions to Span columns. On a JSON error it returns no rows.
func parseOTLP(data []byte, opts Options) ([]Span, error) {
	var p otlpPayload
	if err := json.Unmarshal(data, &p); err != nil {
		return nil, fmt.Errorf("otlp decode: %w", err)
	}
	var rows []Span
	for _, rs := range p.ResourceSpans {
		resAttrs := otlpKVMap(rs.Resource.Attributes)
		for _, ss := range rs.ScopeSpans {
			for _, sp := range ss.Spans {
				rows = append(rows, mapOTLPSpan(sp, resAttrs, opts))
			}
		}
	}
	return rows, nil
}

func mapOTLPSpan(sp otlpSpan, resAttrs map[string]string, opts Options) Span {
	attrs := otlpKVMap(sp.Attributes)

	genAI := telemetry.ExtractGenAIFields(attrs, resAttrs, sp.Name)

View on GitHub (pinned to 3ee70a1026)