Skip to content

UI offline evaluation mishandles OTLP JSON/JSONL traces and crashes with Cannot read properties of undefined (reading 'map') #127

@erauner12

Description

@erauner12

The Web UI's offline evaluation flow appears to mishandle OTLP JSON traces exported as .json/.jsonl.

A Tempo/OTLP trace with top-level resourceSpans works in parts of the app only after renaming from .json to .jsonl, but offline evaluation/upload still has UI-side assumptions that appear to either reject .jsonl or crash client-side with:

Cannot read properties of undefined (reading 'map')

No useful backend error is emitted in this failure mode.

Environment

  • agentevals started with:
agentevals serve --dev
  • Server output:
OTLP HTTP: http://0.0.0.0:4318  (OTEL_EXPORTER_OTLP_ENDPOINT default)
OTLP gRPC: 0.0.0.0:4317  (OTEL_EXPORTER_OTLP_PROTOCOL=grpc)
WebSocket: ws://0.0.0.0:8001/ws/traces
API:       http://0.0.0.0:8001/api
Web UI:    http://localhost:5173
  • Trace source: Tempo v2 / OTLP JSON export
  • Trace shape: top-level resourceSpans

Reproduction

  1. Export an OTLP trace JSON from Tempo or another OTLP source.
  2. The file has top-level shape:
{
  "resourceSpans": [...]
}
  1. Try uploading as trace.otlp.json.

Observed:

Failed to load 'trace.otlp.json': Invalid Jaeger JSON format: expected top-level 'data' key

Server log excerpt:

WARNING:agentevals.api.routes:Failed to load 'trace.otlp.json': Invalid Jaeger JSON format: expected top-level 'data' key in /var/folders/nh/5ff88n4577sfrrqrsf71mkkc0000gp/T/tmpz1mwl3cp/0_trace.otlp.json
INFO:     127.0.0.1:59218 - "POST /api/convert HTTP/1.1" 400 Bad Request
WARNING:agentevals.api.routes:Failed to load 'trace.otlp.json': Invalid Jaeger JSON format: expected top-level 'data' key in /var/folders/nh/5ff88n4577sfrrqrsf71mkkc0000gp/T/tmprk1fftge/0_trace.otlp.json
INFO:     127.0.0.1:59237 - "POST /api/convert HTTP/1.1" 400 Bad Request
WARNING:agentevals.api.routes:Failed to load 'trace.otlp.json': Invalid Jaeger JSON format: expected top-level 'data' key in /var/folders/nh/5ff88n4577sfrrqrsf71mkkc0000gp/T/tmp98dia95n/0_trace.otlp.json
INFO:     127.0.0.1:59277 - "POST /api/convert HTTP/1.1" 400 Bad Request

This suggests the upload path defaults .json to Jaeger even when the content is clearly OTLP.

  1. Rename the same file to:
trace.otlp.jsonl
  1. The trace now works in at least one path because .jsonl selects otlp-json.

Observed successful backend conversion after renaming:

INFO:agentevals.loader.otlp:Loaded 1 trace(s) from /var/folders/nh/5ff88n4577sfrrqrsf71mkkc0000gp/T/tmp5pzdcsg0/0_trace.otlp.jsonl
INFO:agentevals.converter:Auto-detected trace format: adk for trace mdQk80xJsNjJzZnIYcvllg==
INFO:     127.0.0.1:59942 - "POST /api/convert HTTP/1.1" 200 OK
  1. Try using the same .jsonl trace in the offline evaluation UI.

Observed:

Cannot read properties of undefined (reading 'map')

In my run, there was no corresponding useful backend error, suggesting the failure is frontend-side.

One UI path also appeared to mutate the filename in a way that caused it to be treated as Jaeger again:

WARNING:agentevals.api.routes:Failed to load 'trace.otlp.jsonl.json': Invalid Jaeger JSON format: expected top-level 'data' key in /var/folders/nh/5ff88n4577sfrrqrsf71mkkc0000gp/T/tmpxucohlbs/0_trace.otlp.jsonl.json
INFO:     127.0.0.1:59831 - "POST /api/convert HTTP/1.1" 400 Bad Request

Expected behavior

The UI should support OTLP trace uploads consistently across conversion, inspection, and offline evaluation.

At minimum:

  • Trace file upload should accept both .json and .jsonl.
  • Full OTLP JSON files with top-level resourceSpans should be detected as otlp-json, even when the extension is .json.
  • Offline evaluation should pass trace_format: "otlp-json" when the selected trace file is .jsonl or when content detection identifies OTLP.
  • The UI should not crash if the streaming evaluation result shape is missing traceResults; it should show a useful error instead.

Actual behavior

There appear to be several inconsistent assumptions:

  1. .json uploads are treated as Jaeger JSON and fail on OTLP payloads with top-level resourceSpans.
  2. Renaming to .jsonl works around backend format detection.
  3. Offline evaluation UI appears to accept only .json in at least one upload/dropzone path, or otherwise does not handle .jsonl cleanly.
  4. Frontend crashes with:
Cannot read properties of undefined (reading 'map')

Relevant code pointers

  • FileDropZone defaults accept = '.json', which may block or discourage .jsonl trace files in UI upload paths.
  • convertTraces(traceFiles, traceFormat?) supports an optional traceFormat, but TraceProvider.setTraceFiles calls convertTraces(files) without passing one.
  • runEvaluation calls evaluateTracesStreaming(...) with config containing metrics, judge model, threshold, and trajectory match type, but does not include trace_format.
  • The backend accepts .json and .jsonl trace files and infers .jsonl as otlp-json; eval set files are correctly restricted to .json.
  • TraceProvider completion handling does result.traceResults.map(...) without guarding for missing/alternate result shape, which likely explains the frontend crash.

Suggested fix

  1. Add trace-format detection in the frontend or backend based on content:

    • top-level resourceSpans => otlp-json
    • top-level data => jaeger-json
    • Tempo v2 wrapper { "trace": { "resourceSpans": [...] } } could either be supported or emit a targeted error suggesting jq '.trace // .'.
  2. Update trace file upload dropzones to accept:

.json,.jsonl

while keeping eval-set upload restricted to .json.

  1. Ensure offline evaluation passes trace_format: "otlp-json" when appropriate.

  2. Add a defensive guard around:

result.traceResults.map(...)

for example:

const traceResults =
  result.traceResults ??
  (result as any).trace_results ??
  [];

if (!Array.isArray(traceResults)) {
  // surface a useful UI error instead of crashing
}
  1. Add regression tests for:

    • .json OTLP file with top-level resourceSpans
    • .jsonl OTLP file containing full OTLP JSON, not necessarily newline-delimited individual spans
    • offline evaluation UI flow with an OTLP trace
    • malformed/partial SSE completion payload that lacks traceResults

Workaround

For CLI/API usage, explicitly pass OTLP format:

agentevals run trace.otlp.jsonl \
  --format otlp-json \
  --eval-set eval_set.json \
  -m response_match_score

or call the API with:

{
  "trace_format": "otlp-json"
}

For the UI, renaming trace.otlp.json to trace.otlp.jsonl works in some paths but not consistently in offline evaluation.

Human confirmation

  • I am a human user filing this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions