Skip to content

traces get never requests span I/O — every span's input/output is silently null #51

Description

@dark-sorceror

Summary

traceroot traces get never sends the fields query parameter, so the server's default skeleton projection applies and every span comes back with input: null, output: null, metadata: null — the exact payload someone debugging a trace needs. Observed on a real trace: traces get <id> --json returned 0/11 spans with I/O, while the same endpoint called directly with ?fields=full returned 11/11 inputs and 8/11 outputs (including full LLM prompt/completion payloads).

Meanwhile traces export bundles do contain the full payloads in spans.json (the export endpoint defaults to full server-side, per #14). So get and export silently disagree about the same trace, and nothing in help or README says get is the lightweight view. The fields parameter (core/usage/io/metadata, aliases skeleton/full) is already documented in the CLI's vendored openapi.json — the capability exists end to end; the client just never uses it.

How to replicate

  1. Pick a trace with LLM traffic from traceroot traces list.
  2. traceroot traces get <trace_id> --json | jq '[.spans[] | {name, input, output}]' — every span's input/output is null.
  3. curl -H "Authorization: Bearer tr-..." "<host>/api/v1/public/traces/<trace_id>?fields=full" | jq '[.spans[] | {name, input, output}]' — payloads are populated.
  4. traceroot traces export <trace_id> --output ./bundle./bundle/spans.json has the full payloads. Same CLI, same trace, two contradictory answers about whether I/O was captured.

Root cause (confirmed)

  • getTrace (src/api/client.ts:153-155) builds the URL with no query string, and neither traces get nor traces export exposes a --fields flag (src/commands/traces/get.ts:92-102 registers only <traceId>).
  • The vendored openapi.json documents the parameter and its default: skeleton unless fields=full (or fields=io,metadata) is passed; the server validates unknown groups with a 400.
  • Nothing documents the get/export asymmetry, so a consumer scripting against traces get --json concludes the payloads were never captured and stops investigating.

Impact

  • The core debugging question — what did the model actually receive and return? — cannot be answered by the primary read command.
  • Automated consumers see uniform null I/O with no error and report "inputs/outputs were not captured", which is wrong.
  • The only workaround is a disk round-trip (traces export → read spans.json → clean up).

Acceptance criteria

  • traceroot traces get <id> --fields <groups> passes the value through to the server verbatim (a 400 for unknown groups surfaces as a normal CLI error).
  • traceroot traces export accepts the same flag (default remains full).
  • The default projection for traces get is documented in --help and the README, including how to get span I/O.
  • Stretch: traceroot traces get <id> --span <span_id> fetches a single span's untruncated input/output, so consumers can inspect one suspicious span without a full fetch.
  • A test pins that the requested fields value appears in the outgoing request URL.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions