JuliusBrussee/caveman · error
otlp decode: %w
Error message
otlp decode: %w
What it means
parseOTLP unmarshals the payload into a strictly typed otlpPayload (OTLP/JSON trace export shape: resourceSpans -> scopeSpans -> spans). Any JSON error is wrapped as 'otlp decode: %w'. Note the doc comment: on a JSON error it returns no rows — partial data is never emitted. Type mismatches on nested OTLP fields (e.g. traceId expected as hex string but given object) surface here too.
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 27d5a3981a)
Solutions
- Confirm the payload is OTLP/JSON traces (resourceSpans at the root), not protobuf or another signal type
- Read the wrapped json error for the offending offset/field and validate the document against the OTLP JSON schema
- If exporting from a collector, set exporters to JSON encoding explicitly
- Re-fetch or re-export the batch if truncation is suspected
Example fix
// before rows, sum, err := importers.Import(importers.FormatOTLP, protoBytes, opts) // binary OTLP // after jsonBytes, _ := protoToJSONOtlp(protoBytes) // encode via collector or protojson rows, sum, err := importers.Import(importers.FormatOTLP, jsonBytes, opts)
Defensive patterns
Strategy: validation
Validate before calling
func looksLikeOTLPJSON(data []byte) bool {
d := bytes.TrimSpace(data)
return len(d) > 0 && d[0] == '{' && bytes.Contains(d, []byte("resourceSpans"))
} Try / catch
if _, _, err := importers.Import(importers.FormatOTLP, raw, opts); err != nil { if strings.Contains(err.Error(), "otlp decode") { return fmt.Errorf("payload is not OTLP/JSON traces: %w", err) } } Prevention
- Configure OTLP exporters to JSON encoding explicitly in the collector
- Never feed protobuf OTLP bytes to the JSON importer; convert first
- Smoke-test one batch with a JSON schema check before bulk import
When it happens
Trigger: Feeding OTLP/proto (binary) bytes to a JSON parser; a truncated export; passing an OTLP metrics or logs export instead of traces; an exporter emitting non-standard JSON where a span field has the wrong type; feeding the generic {'data':...} shape to the otlp format.
Common situations: Confusing content-type between protobuf and JSON OTLP encodings on the collector; version skew with pre-release OTLP JSON schemas; proxy or LB truncating large trace batches; testing with a hand-written JSON file missing required nesting.
Related errors
- generic decode: expected a JSON array or {"data":[...]} of o
- helicone decode: %w
- langfuse decode: %w
- corpus provider conversion supports string or null content
- cachebench: verifier returned duplicate or invalid JSON
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/cd5b916502fc1a70.
Report an issue: GitHub.