TauricResearch/TradingAgents · error · ValueError

ticker exceeds {max_len} chars: {value!r}

Error message

ticker exceeds {max_len} chars: {value!r}

What it means

Raised by safe_ticker_component() in tradingagents/dataflows/utils.py when the string is longer than max_len (default 32). It bounds the ticker before it is used as a filesystem path component — the guard exists because overlong or hostile values flow into os.path.join/Path from user or LLM input.

Source

Thrown at tradingagents/dataflows/utils.py:32

_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 the actual exchange ticker (almost always < 10 chars)
  2. Validate/truncate LLM tool output before it reaches dataflows: extract the symbol with a regex like ^[A-Za-z0-9._^=+-]{1,16}$
  3. Raise max_len only if you genuinely support longer path components (call-site kwarg), not to paper over bad input

Example fix

# before
safe_ticker_component("Apple Incorporated Class A Common Stock")
# -> ValueError: ticker exceeds 32 chars: ...

# after
safe_ticker_component("AAPL")
# or constrain LLM output first
import re
m = re.search(r"\b[A-Z]{1,5}(?:\.[A-Z]{1,2})?\b", raw)
safe_ticker_component(m.group(0)) if m else reject()
Defensive patterns

Strategy: validation

Validate before calling

def ticker_length_ok(value: str, max_len: int = 32) -> bool:
    return isinstance(value, str) and 0 < len(value) <= max_len

Type guard

def looks_like_ticker(v) -> bool:
    import re
    return isinstance(v, str) and bool(re.fullmatch(r"[A-Za-z0-9._\-^=+]{1,16}", v)) and set(v) != {"."}

Try / catch

try:
    safe_ticker_component(raw)
except ValueError as e:
    if "exceeds" in str(e):
        m = re.search(r"[A-Za-z0-9._\-^=+]{1,16}", raw)   # extract the embedded symbol
        raw = m.group(0) if m else None
    raise

Prevention

When it happens

Trigger: Passing full company names, sentences, pasted text blobs, or prompt-injected content as a ticker; concatenating exchange prefixes/suffixes beyond 32 chars (rare for real tickers, which are short).

Common situations: LLM passing the company name instead of the symbol ('Apple Inc.' style, or worse, whole phrases); upstream schemas losing validation; users pasting ISINs plus descriptions.

Related errors


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