# How to Debug Analysis Issues Using the Agent State Propagation System in TradingAgents-CN

> Debug analysis issues in TradingAgents-CN by enabling debug mode and inspecting performance metrics to pinpoint analyst node failures or timeouts during state propagation.

- Repository: [hsliuping/TradingAgents-CN](https://github.com/hsliuping/tradingagents-cn)
- Tags: how-to-guide
- Published: 2026-02-16

---

**Enable `debug=True` in `TradingAgentsGraph` and inspect `performance_metrics` in the returned state to trace exactly which analyst node failed or timed out during propagation.**

The **TradingAgents-CN** repository implements a multi-agent analysis pipeline where the `TradingAgentsGraph` class orchestrates specialized analysts (market, social, news, fundamentals) through a state-propagation mechanism. When stock analysis results are missing, delayed, or incorrect, debugging the **agent state propagation system** is the most direct path to resolution.

## Understanding the State-Propagation Architecture

### Core Components

The propagation logic lives in [`tradingagents/graph/trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/graph/trading_graph.py). The `TradingAgentsGraph` class exposes the `propagate()` method, which is invoked by `run_stock_analysis()` in [`web/utils/analysis_runner.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/web/utils/analysis_runner.py).

When you call `graph.propagate(company_name, trade_date)`, the system:

1. Creates an initial agent state via `self.propagator.create_initial_state()`
2. Sets up per-node timing dictionaries (`node_timings`, `total_start_time`)
3. Selects stream mode (`updates` vs `values`) based on whether a `progress_callback` is provided
4. Executes the LangChain-style graph, optionally tracing LLM messages when `debug=True`

### The Propagation Pipeline

The `propagate()` method follows a strict sequence that provides natural debugging hooks:

| Step | Debugging Relevance | Source Location |
|------|---------------------|-----------------|
| **Parameter logging** | Verify `company_name`, `trade_date`, and `task_id` are correctly passed | [`trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/trading_graph.py) lines 72-88 |
| **Initial state creation** | Inspect empty slots for all analysts before execution | [`trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/trading_graph.py) lines 92-98 |
| **Debug/tracing branch** | When `self.debug` is `True`, prints every LLM message via `pretty_print()` | [`trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/trading_graph.py) lines 111-150 |
| **Progress updates** | Real-time UI feedback via `_send_progress_update()` | [`trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/trading_graph.py) line 934 |
| **Node timing** | Captures elapsed time per node to identify bottlenecks | [`trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/trading_graph.py) lines 161-176 |
| **Final state assembly** | Attaches `performance_metrics` including `node_timings` and total duration | [`trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/trading_graph.py) lines 211-232 |
| **State persistence** | Logs final state via `_log_state()` for post-hoc analysis | [`trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/trading_graph.py) lines 236-242 |

## Three Strategic Debugging Breakpoints

### Input Validation

Before the graph executes, `propagate()` logs the raw input parameters. If your analysis returns data for the wrong symbol or date, check the logs at the start of `propagate()` to confirm the `company_name` and `trade_date` values match your request.

### Node-Level Execution

Enable **debug tracing** by setting `debug=True` when constructing `TradingAgentsGraph`. This activates the trace branch that prints every LLM message using `pretty_print()`. When an analyst node fails or returns malformed JSON, the trace shows the exact prompt and response, making it trivial to spot API key errors, rate limits, or schema mismatches.

### Performance and State Inspection

After `propagate()` returns, inspect `graph.curr_state` (or the returned `state` dictionary). This contains the complete agent state tree, including intermediate reports like `market_report`, `fundamentals_report`, and `risk_assessment`. The `performance_metrics` field provides per-node timings that pinpoint exactly which analyst is causing delays.

## Common Debugging Scenarios and Fixes

**Missing Analyst Output**
If `fundamentals_report` is empty in the final state, examine the trace logs for the **Fundamentals** node. Verify that the `FINNHUB_API_KEY` environment variable is set and that the node's tool function succeeded. If the API call fails, add the required credential or replace the tool with a fallback defined in [`trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/trading_graph.py).

**Timeout or Long-Running Node**
Check `node_timings` in `performance_metrics`. Nodes exceeding a few seconds indicate LLM timeouts. Increase the `timeout` value in `quick_model_config` or `deep_model_config` within your configuration, or switch to a faster model provider.

**Incorrect Progress Display**
If the UI shows stale progress bars, verify that `progress_callback` is being invoked for each chunk via `_send_progress_update`. Ensure the caller passes a valid callback function; the `run_stock_analysis` wrapper handles this automatically when called from the Streamlit UI.

**Missing Performance Metrics**
If the returned state lacks timing data, confirm you are reading from `result['performance_metrics']`. The timing logic executes regardless of the `debug` flag, so metrics are always available unless the graph execution itself crashes before completion.

**Unexpected Model Info**
When logs show "Unknown" for the model identifier, the LLM wrapper may not expose `model_name`. Verify that your provider's `ChatOpenAI` subclass implements this attribute, or manually set `model_info` in the configuration dictionary passed to `TradingAgentsGraph`.

## Practical Debugging Code Examples

### Enabling Full Debug Tracing

```python
from tradingagents.graph.trading_graph import TradingAgentsGraph
from tradingagents.default_config import DEFAULT_CONFIG
import logging

# Turn on verbose logging for the web logger

logging.getLogger('web').setLevel(logging.DEBUG)

# Create the graph with debug tracing enabled

graph = TradingAgentsGraph(
    selected_analysts=["market", "social", "news", "fundamentals"],
    debug=True,  # Activates pretty_print of every node

    config=DEFAULT_CONFIG
)

# Run propagation without UI callback for cleaner logs

state, decision = graph.propagate(
    company_name="AAPL",
    trade_date="2024-08-01"
)

# Inspect performance bottlenecks

print("Node timings:")
for node, secs in state["performance_metrics"]["node_timings"].items():
    print(f"  {node:30s} → {secs:.2f}s")

```

### Monitoring Live Progress with Callbacks

```python
def my_progress(chunk, step=None, total=None):
    # chunk is a dict {node_name: partial_state}

    for node, update in chunk.items():
        if not node.startswith("__"):
            print(f"[{node}] updated – keys: {list(update.keys())}")

# Normal production run with progress tracking

graph = TradingAgentsGraph(debug=False, config=DEFAULT_CONFIG)
state, decision = graph.propagate(
    company_name="TSLA",
    trade_date="2024-08-01",
    progress_callback=my_progress,  # Receives updates from _send_progress_update

    task_id="demo123"
)

```

### Diagnosing Failed Analyst Nodes

```python

# After a failed run, inspect graph.curr_state

failed_node = "Fundamentals Analyst"
state = graph.curr_state

if failed_node in state:
    print(f"Output found:\n{state[failed_node]}")
else:
    # Check if node was skipped due to missing API keys

    timings = state.get("performance_metrics", {}).get("node_timings", {})
    if failed_node not in timings:
        print(f"{failed_node} did not execute – verify FINNHUB_API_KEY")

```

## Key Files for Deep Debugging

| File | Purpose | Location |
|------|---------|----------|
| [`tradingagents/graph/trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/graph/trading_graph.py) | Core graph definition, `propagate()` implementation, timing logic, and debug tracing | [View on GitHub](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/graph/trading_graph.py) |
| [`web/utils/analysis_runner.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/web/utils/analysis_runner.py) | High-level wrapper `run_stock_analysis()` that instantiates the graph and handles UI integration | [View on GitHub](https://github.com/hsliuping/TradingAgents-CN/blob/main/web/utils/analysis_runner.py) |
| [`tradingagents/default_config.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/default_config.py) | Default LLM configurations including timeout settings for `quick_model_config` and `deep_model_config` | [View on GitHub](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/default_config.py) |
| [`web/run_web.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/web/run_web.py) | Streamlit UI entry point that provides the `progress_callback` implementation | [View on GitHub](https://github.com/hsliuping/TradingAgents-CN/blob/main/web/run_web.py) |
| [`tradingagents/utils/logging_manager.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/utils/logging_manager.py) | Logging infrastructure used throughout the propagation system | [View on GitHub](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/utils/logging_manager.py) |

## Summary

- **Enable `debug=True`** when constructing `TradingAgentsGraph` to trace every LLM message and identify which analyst node produces malformed output or failures.
- **Inspect `performance_metrics`** in the returned state dictionary to pinpoint timeout bottlenecks via per-node timings stored in `node_timings`.
- **Validate inputs** by checking the initial logs in `propagate()` to confirm `company_name` and `trade_date` match your request before the graph executes.
- **Use `progress_callback`** to monitor real-time state updates during long-running analyses, ensuring the UI reflects actual node completion status.
- **Check `curr_state`** after execution to examine raw analyst outputs (e.g., `fundamentals_report`) and verify API credentials when nodes are missing from the state tree.

## Frequently Asked Questions

### How do I enable detailed logging to see exactly what each analyst node is doing?

Set `debug=True` when creating the `TradingAgentsGraph` instance. This activates the trace branch in [`trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/trading_graph.py) (lines 111-150) which calls `pretty_print()` on every LLM message. You should also set `logging.getLogger('web').setLevel(logging.DEBUG)` to capture parameter logs at the start of `propagate()`.

### Where can I find timing information to identify slow analyst nodes?

The `propagate()` method automatically records execution times in the `performance_metrics` dictionary returned as part of the final state. Specifically, `state["performance_metrics"]["node_timings"]` contains a mapping of each analyst node name to its elapsed time in seconds. Check this dictionary after `graph.propagate()` returns to identify bottlenecks.

### What should I check if a specific analyst report is missing from the final state?

First, verify that the analyst appears in `state["performance_metrics"]["node_timings"]`. If the node is absent from the timings dictionary, it likely failed to execute due to missing API credentials (e.g., `FINNHUB_API_KEY` for fundamentals) or an exception during tool invocation. Check the trace logs when `debug=True` to see the exact error message from the LLM or tool node.

### How does the progress callback work for real-time UI updates?

The `progress_callback` parameter in `propagate()` receives chunks from the graph stream via `_send_progress_update()` (line 934 in [`trading_graph.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/trading_graph.py)). Each chunk is a dictionary mapping node names to partial state updates. When `debug=False` and a callback is provided, the graph runs in `updates` mode, allowing the UI to render progress bars as each analyst completes its work.