mlflow/mlflow · error · TypeError

TraceData.from_dict() expects a dictionary. Got: {type(d).__

Error message

TraceData.from_dict() expects a dictionary. Got: {type(d).__name__}

What it means

TypeError raised by the classmethod TraceData.from_dict when the argument is not a dict. from_dict expects a mapping containing at least a 'spans' key (default []).

Source

Thrown at mlflow/entities/trace_data.py:28

@dataclass
class TraceData:
    """A container object that holds the spans data of a trace.

    Args:
        spans: List of spans that are part of the trace.
    """

    spans: list[Span] = field(default_factory=list)

    # NB: Custom constructor to allow passing additional kwargs for backward compatibility for
    # DBX agent evaluator. Once they migrates to trace V3 schema, we can remove this.
    def __init__(self, spans: list[Span] | None = None, **kwargs):
        self.spans = spans or []

    @classmethod
    def from_dict(cls, d):
        if not isinstance(d, dict):
            raise TypeError(f"TraceData.from_dict() expects a dictionary. Got: {type(d).__name__}")
        return cls(spans=[Span.from_dict(span) for span in d.get("spans", [])])

    def to_dict(self) -> dict[str, Any]:
        return {"spans": [span.to_dict() for span in self.spans]}

    # TODO: remove this property in 3.7.0
    @property
    @deprecated(since="3.6.0", alternative="trace.search_spans(name=...)")
    def intermediate_outputs(self) -> dict[str, Any] | None:
        """
        .. deprecated:: 3.6.0
            Use `trace.search_spans(name=...)` to search for spans and get the outputs.

        Returns intermediate outputs produced by the model or agent while handling the request.
        There are mainly two flows to return intermediate outputs:
        1. When a trace is generate by the `mlflow.log_trace` API,
        return `intermediate_outputs` attribute of the span.
        2. When a trace is created normally with a tree of spans,

View on GitHub (pinned to 6a27f2decc)

Solutions

  1. Parse JSON first: TraceData.from_dict(json.loads(s)) instead of passing the raw string
  2. Wrap non-dict payloads: if isinstance(d, str): d = json.loads(d)
  3. Ensure the JSON file has a top-level object like {"spans": [...]}
  4. If you already have a TraceData, do not round-trip through from_dict

Example fix

// before
TraceData.from_dict(open('trace.json').read())
// after
import json
TraceData.from_dict(json.loads(open('trace.json').read()))
Defensive patterns

Strategy: validation

Validate before calling

import json
if isinstance(d, str):
    d = json.loads(d)
if not isinstance(d, dict):
    raise ValueError('trace payload must be a JSON object/dict')

Type guard

def is_trace_dict(d) -> bool:
    return isinstance(d, dict) and isinstance(d.get('spans', []), list)

Try / catch

try:
    trace = TraceData.from_dict(d)
except TypeError:
    import json
    trace = TraceData.from_dict(json.loads(d))

Prevention

When it happens

Trigger: Calling `TraceData.from_dict(json_string)` (passing a str), `TraceData.from_dict(list_of_spans)`, or `TraceData.from_dict(None)`; passing output of json.loads on a non-object JSON payload.

Common situations: Loading a trace from a JSON file that is a top-level array; passing the result of json.dumps (a string) instead of json.loads; passing a TraceData object instead of its to_dict() output.

Related errors


AI-assisted analysis of mlflow/mlflow@6a27f2decc (2026-08-29). Data as JSON: /api/errors/b4e14b77b69d1df1. Report an issue: GitHub.