TauricResearch/TradingAgents · error · ValueError

ticker contains characters not allowed in a filesystem path:

Error message

ticker contains characters not allowed in a filesystem path: {value!r}

What it means

Raised by safe_ticker_component() in tradingagents/dataflows/utils.py when the string contains characters outside _TICKER_PATH_RE = ^[A-Za-z0-9._\-^=+]+$. That allowlist deliberately excludes slashes, spaces, colons, percent, etc., so the value can never traverse directories when interpolated into cache/checkpoint/result paths. Legit symbol punctuation (dot, dash, caret for indices, '=' for futures, '+' for forex) is permitted.

Source

Thrown at tradingagents/dataflows/utils.py:34

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}")


def get_current_date():
    return date.today().strftime("%Y-%m-%d")

View on GitHub (pinned to a33fd4c0f1)

Solutions

  1. Use canonical Yahoo-style symbols with allowed punctuation only: 'AAPL', 'BRK-B'/'BRK.B', '^GSPC', 'GC=F', 'XAUUSD+'
  2. Replace disallowed separators before passing: ' ' -> '-' or '.', strip ':EXCHANGE' suffixes
  3. Treat this error as a security signal: if it fires from LLM tool output, audit the pipeline for prompt injection instead of sanitizing blindly
  4. Pre-validate with the same pattern: re.fullmatch(r'[A-Za-z0-9._\-^=+]+', value)

Example fix

# before
safe_ticker_component("../../../etc/passwd")   # or "AAPL/BTC"
# -> ValueError: ticker contains characters not allowed in a filesystem path: ...

# after
safe_ticker_component("AAPL")
# pre-validate
import re
ok = bool(re.fullmatch(r"[A-Za-z0-9._\-^=+]", value)) and set(value) != {"."}
safe_ticker_component(value) if ok else reject()
Defensive patterns

Strategy: validation

Validate before calling

import re
from tradingagents.dataflows.utils import safe_ticker_component

def sanitize_ticker(raw: str) -> str | None:
    """Return a path-safe ticker or None; mirrors safe_ticker_component's rules."""
    if not isinstance(raw, str):
        return None
    raw = raw.strip().replace(" ", "-")          # 'BRK B' -> 'BRK-B'
    raw = raw.split(":")[0]                        # strip 'AAPL:US' suffixes
    if not re.fullmatch(r"[A-Za-z0-9._\-^=+]+", raw) or set(raw) == {"."}:
        return None
    return raw

Type guard

import re

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

Try / catch

try:
    safe_ticker_component(ticker)
except ValueError as e:
    if "not allowed in a filesystem path" in str(e):
        # SECURITY signal: input may be prompt-injected; log & reject, don't sanitize blindly
        security_log(f"rejected suspicious ticker {ticker!r}")
        raise
    raise

Prevention

When it happens

Trigger: Values like '../../../etc/passwd', 'AAPL/BTC', 'BRK B' (space instead of dot), 'AAPL:US' (colon), URL-encoded or prompt-injected strings containing '/' or '%'. Any path separator or exotic punctuation triggers it.

Common situations: Prompt injection embedded in fetched news/newsletter text reaching ticker fields; users typing 'BRK B' or exchange-suffixed forms; values URL-decoded late; pipe-delimited lists passed as one symbol.

Related errors


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