TauricResearch/TradingAgents · error · ValueError

ticker must be a non-empty string, got {value!r}

Error message

ticker must be a non-empty string, got {value!r}

What it means

Raised by safe_ticker_component() in tradingagents/dataflows/utils.py when the value is not a str instance or is the empty string. It is the first of four ValueError guards that vet ticker-like values before they are interpolated into filesystem paths (cache/checkpoint/results), because tickers arrive from user CLI input or LLM tool calls that can be attacker-influenced via prompt injection.

Source

Thrown at tradingagents/dataflows/utils.py:30

# traversal, so the value never escapes a containing directory when
# interpolated into a path. Anything else is rejected.
_TICKER_PATH_RE = re.compile(r"^[A-Za-z0-9._\-\^=+]+$")


def safe_ticker_component(value: str, *, max_len: int = 32) -> str:
    """Validate ``value`` is safe to interpolate into a filesystem path.

    Tickers come from user CLI input or from LLM tool calls, both of which
    can be influenced by attacker-controlled content (e.g. prompt injection
    embedded in fetched news). Without validation, a value like
    ``"../../../etc/foo"`` flows into ``os.path.join`` / ``Path /`` and
    escapes the configured cache, checkpoint, or results directory.

    Returns ``value`` unchanged when it matches the allowed pattern; raises
    ``ValueError`` otherwise.
    """
    if not isinstance(value, str) or not value:
        raise ValueError(f"ticker must be a non-empty string, got {value!r}")
    if len(value) > max_len:
        raise ValueError(f"ticker exceeds {max_len} chars: {value!r}")
    if not _TICKER_PATH_RE.fullmatch(value):
        raise ValueError(
            f"ticker contains characters not allowed in a filesystem path: {value!r}"
        )
    # The regex above allows '.', so values like '.', '..', '...' would pass,
    # and as a path component they traverse the parent directory. Reject any
    # value that's only dots.
    if set(value) == {"."}:
        raise ValueError(f"ticker cannot consist solely of dots: {value!r}")
    return value


def save_output(data: pd.DataFrame, tag: str, save_path: SavePathType = None) -> None:
    if save_path:
        data.to_csv(save_path, encoding="utf-8")
        print(f"{tag} saved to {save_path}")

View on GitHub (pinned to a33fd4c0f1)

Solutions

  1. Pass a concrete non-empty string ticker, e.g. 'AAPL'
  2. Guard Optionals at the boundary: if not ticker: raise/return before calling
  3. Coerce numeric ids to str at ingestion and validate they look like tickers

Example fix

# before
safe_ticker_component(None)      # or "" or 42
# -> ValueError: ticker must be a non-empty string, got None

# after
if not isinstance(ticker, str) or not ticker:
    raise ValueError("ticker required")
safe_ticker_component(ticker)
Defensive patterns

Strategy: type-guard

Validate before calling

def require_ticker(value) -> str:
    if not isinstance(value, str) or not value.strip():
        raise ValueError(f"ticker required, got {value!r}")
    return value.strip()

Type guard

def is_nonempty_str(v) -> bool:
    return isinstance(v, str) and v != ""

Try / catch

try:
    safe_ticker_component(ticker)
except ValueError as e:
    if "non-empty string" in str(e):
        ticker = "SPY"  # or reject the tool call / re-prompt the LLM
    else:
        raise

Prevention

When it happens

Trigger: Passing None, an int (e.g. a numeric ticker id), a pandas/numpy scalar, or '' as a symbol to any code path that builds a path from it; Optional[str] fields forwarded without a None check.

Common situations: LLM tool schemas marking ticker optional and the model omitting it; data pipelines passing stock ids as integers; deserialized JSON where the field is null; empty-string defaults from CLI argparse.

Related errors


AI-assisted analysis of TauricResearch/TradingAgents@a33fd4c0f1 (2026-08-14). Data as JSON: /api/errors/a4796019f76221d8. Report an issue: GitHub.