> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uselemma.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Good trace vs bad trace

> Side-by-side examples of malformed vs conformant traces, with the one-line cause and fix for each

Lemma reads a specific [trace contract](/reference/trace-contract): one agent execution is **one trace** with a single root span, and every LLM call, tool call, and unit of work is a **child span** of that root. When a trace does not match this shape, Lemma can still render what it receives, but input/output, model and token stats, tool visibility, and automated issue detection degrade.

This page shows the four most common malformed shapes next to their conformant counterparts. Each tree is drawn the same way as in [Traces](/tracing/instrumentation/traces): the root is the trace, indented lines are child spans.

<Note>
  **One agent execution = one trace.** If you fix only one thing, make every LLM and tool call a child span of a single root rather than its own top-level trace.
</Note>

## Sibling traces vs one nested trace

The most common problem: each LLM or tool call is exported as its own top-level trace, so a single agent run is scattered across three unrelated traces.

**Bad** - three sibling traces, one per call:

```text theme={null}
draft-reply                <- trace (generation, no parent)

search_docs                <- trace (tool call, no parent)

final-answer               <- trace (generation, no parent)
```

**Good** - one trace, calls nested under the root:

```text theme={null}
support-agent              <- trace root (input, output)
|- draft-reply             <- generation
|- search_docs             <- tool call
`- final-answer            <- generation
```

* **Cause:** child work ran without an explicit root trace or trace ID, or it crossed a queue, worker, stream, or timer without carrying the trace handle/IDs with it.
* **Fix:** wrap the run with `lemma.trace()` and record child work with `trace.recordGeneration()` / `trace.record_generation()`, `trace.recordTool()` / `trace.record_tool()`, and `trace.recordSpan()` / `trace.record_span()` inside it. See [Traces](/tracing/instrumentation/traces) and [Every span appears as a separate trace](/tracing/troubleshooting/common-issues#every-span-appears-as-a-separate-trace).

## Empty root vs root with input and output

A trace whose root carries no input or output shows only timing. You cannot read what the user asked, what the agent answered, or whether the run succeeded.

**Bad** - root with no input/output:

```text theme={null}
support-agent              <- trace root (no input, no output)
|- draft-reply             <- generation
`- search_docs             <- tool call
```

**Good** - root carries the user input and the final answer:

```text theme={null}
support-agent              <- trace root
                             input:  "Where is my order #1843?"
                             output: "It ships tomorrow and arrives Friday."
|- draft-reply             <- generation
`- search_docs             <- tool call
```

* **Cause:** the root span was never given input/output (or the work was recorded only on children).
* **Fix:** pass `input` to `lemma.trace()` and return the final answer from the callback. Use `trace.output(output)` for custom output and `trace.fail(error)` before re-raising errors. See [Traces](/tracing/instrumentation/traces).

## Invisible tool calls vs typed tool spans

Provider instrumentation usually captures model calls but not your application tools, so the model is visible while the tools it called are not. Even when a tool span exists, an untyped one with no args or result is opaque.

**Bad** - provider/LLM spans present, tool calls invisible:

```text theme={null}
support-agent              <- trace root
|- draft-reply             <- generation
`- final-answer            <- generation
                             (search_docs ran but was never traced)
```

**Good** - each tool is a child span typed as a tool, with args and result:

```text theme={null}
support-agent              <- trace root
|- draft-reply             <- generation
|- search_docs             <- tool call
|                            input:  { "query": "order 1843 status" }
|                            output: { "status": "shipped", "eta": "Fri" }
`- final-answer            <- generation
```

* **Cause:** tools are invoked outside any span, or are wrapped in a generic span that is not typed as a tool.
* **Fix:** record each completed tool call with `trace.recordTool({ name, input, output })` or `trace.record_tool(name=..., input=..., output=...)`. The SDK records the arguments, result, and tool kind attributes Lemma reads. See [Tool calls](/tracing/instrumentation/tool-calls).

## Flat nesting vs a proper parent/child tree

Spans can all exist yet sit as siblings under the root, losing the structure of which step called which. A flat list hides retries, sub-agents, and the retrieval that fed a generation.

**Bad** - flat: every span is a direct child of the root:

```text theme={null}
support-agent              <- trace root
|- plan                    <- span
|- embed-query             <- generation
|- search_docs             <- tool call
|- rerank                  <- span
`- final-answer            <- generation
```

**Good** - work nests under the step that performed it:

```text theme={null}
support-agent              <- trace root
|- plan                    <- span
|  `- embed-query          <- generation
|- retrieve                <- span
|  |- search_docs          <- tool call
|  `- rerank               <- span
`- final-answer            <- generation
```

* **Cause:** child spans are created without the explicit parent span handle or parent ID, so everything attaches to the root.
* **Fix:** record child work from the `trace` or span handle passed into the helper. Use `trace.startSpan()` / `trace.start_span()` when a subtask needs its own measured parent span. See [Trace nesting is flat](/tracing/troubleshooting/common-issues#trace-nesting-is-flat).

## Current issue-detection support

Beyond rendering a trace, Lemma runs automated **issue detection** (silent failures, bad tool calls, loops). Today this runs for traces that arrive in a recognized shape:

* Lemma SDK traces produced by `lemma.trace()` with `trace.recordGeneration()` / `trace.record_generation()` and `trace.recordTool()` / `trace.record_tool()` child records.

A conformant trace (one root, input/output, typed generation and tool children) is the best way to get full value and to be eligible for issue detection.

<CardGroup cols={2}>
  <Card title="Trace contract" icon="file-check" href="/reference/trace-contract">
    The exact shape and fields Lemma reads.
  </Card>

  <Card title="Common issues" icon="bug" href="/tracing/troubleshooting/common-issues">
    Symptoms, causes, and fixes for malformed traces.
  </Card>

  <Card title="Traces" icon="git-branch" href="/tracing/instrumentation/traces">
    Wrap one agent execution in one trace.
  </Card>

  <Card title="Tool calls" icon="wrench" href="/tracing/instrumentation/tool-calls">
    Record tool args and results as child spans.
  </Card>
</CardGroup>
