jaegertracing/jaeger · error
cannot copy stored trace: %w
Error message
cannot copy stored trace: %w
What it means
memory store's cloneTrace deep-copies a stored trace by marshal/unmarshal round-trip. If marshaling the source traces fails, it returns this error so callers never get a trace aliasing internal state — the memory store promises callers fully modifiable copies. pdata does not normally fail for well-formed traces, so this usually indicates corrupted internal state.
Source
Thrown at internal/storage/v2/memory/memory.go:189
// reader that modifies what it received would rewrite the stored trace for
// every later reader. Query-time adjusters do exactly that — the adjuster
// interface is documented as modifying a trace in place — as does any
// query-interceptor extension that redacts attributes on the return path.
//
// This restores for the v2 store the guarantee #2720 added to the v1 store,
// which was lost when the v1 implementation was deleted in #7711, and it uses
// the same mechanism. A proto round-trip is the only copy that is deep for every
// field: ptrace.Traces.CopyTo looks like the cheaper equivalent, but it assigns
// bytes-valued attributes by slice (`ov.BytesValue = t.BytesValue` in pdata's
// generated CopyAnyValue), leaving the clone sharing a backing array with the
// store, which a reader can then rewrite through pcommon.ByteSlice.SetAt.
// Nested array and kvlist values are copied properly, so bytes are the only
// gap — but relying on that is how this class of bug survives, and the contract
// this upholds promises callers a trace they may modify however they like.
func cloneTrace(src ptrace.Traces) (ptrace.Traces, error) {
buf, err := marshalTraces(src)
if err != nil {
return ptrace.Traces{}, fmt.Errorf("cannot copy stored trace: %w", err)
}
dst, err := unmarshalTraces(buf)
if err != nil {
return ptrace.Traces{}, fmt.Errorf("cannot copy stored trace: %w", err)
}
return dst, nil
}
// Indirected so that tests can exercise cloneTrace's error paths, which pdata
// does not produce for a well-formed trace held by the store.
var (
marshalTraces = new(ptrace.ProtoMarshaler).MarshalTraces
unmarshalTraces = new(ptrace.ProtoUnmarshaler).UnmarshalTraces
)
func (st *Store) GetDependencies(ctx context.Context, query depstore.QueryParameters) ([]model.DependencyLink, error) {
m := st.getTenant(tenancy.GetTenant(ctx))
return m.getDependencies(query)View on GitHub (pinned to 806f444784)
Solutions
- Report/investigate the underlying marshal error — the stored trace is malformed
- Re-ingest or evict the affected trace from the store
- Check jaeger/pdata version compatibility if traces came from deserialization
Defensive patterns
Strategy: try-catch
Try / catch
clone, err := cloneTrace(src)
if err != nil {
// stored trace is unusable: log wrapped cause, skip or evict trace
return fmt.Errorf("skipping corrupt trace: %w", err)
} Prevention
- Treat cloneTrace errors as store-corruption signals worth investigating
- Keep pdata/jaeger versions consistent
- Exercise the marshal/unmarshal indirection hooks in tests
- Validate traces at ingestion boundaries
When it happens
Trigger: Calling cloneTrace (via the memory store's read/copy paths) when marshalTraces(src) returns an error, e.g. corrupt pdata held in the store.
Common situations: Rare in practice; indicates a bug or corrupted in-memory trace data; surfaced in tests via the indirection hooks of marshalTraces/unmarshalTraces.
Related errors
- unknown encoding type: %#02x
- unknown encoding type: %#02x
- unknown column for position: %q
- invalid TraceID length: %d
- failed to marshal slice attribute %q: %w
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/6e0eae4d9ef151e9.
Report an issue: GitHub.