{"record":{"id":"a4796019f76221d8","repo":"TauricResearch/TradingAgents","slug":"ticker-must-be-a-non-empty-string-got-value-r","errorCode":null,"errorMessage":"ticker must be a non-empty string, got {value!r}","messagePattern":"ticker must be a non-empty string, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tradingagents/dataflows/utils.py","lineNumber":30,"sourceCode":"# traversal, so the value never escapes a containing directory when\n# interpolated into a path. Anything else is rejected.\n_TICKER_PATH_RE = re.compile(r\"^[A-Za-z0-9._\\-\\^=+]+$\")\n\n\ndef safe_ticker_component(value: str, *, max_len: int = 32) -> str:\n    \"\"\"Validate ``value`` is safe to interpolate into a filesystem path.\n\n    Tickers come from user CLI input or from LLM tool calls, both of which\n    can be influenced by attacker-controlled content (e.g. prompt injection\n    embedded in fetched news). Without validation, a value like\n    ``\"../../../etc/foo\"`` flows into ``os.path.join`` / ``Path /`` and\n    escapes the configured cache, checkpoint, or results directory.\n\n    Returns ``value`` unchanged when it matches the allowed pattern; raises\n    ``ValueError`` otherwise.\n    \"\"\"\n    if not isinstance(value, str) or not value:\n        raise ValueError(f\"ticker must be a non-empty string, got {value!r}\")\n    if len(value) > max_len:\n        raise ValueError(f\"ticker exceeds {max_len} chars: {value!r}\")\n    if not _TICKER_PATH_RE.fullmatch(value):\n        raise ValueError(\n            f\"ticker contains characters not allowed in a filesystem path: {value!r}\"\n        )\n    # The regex above allows '.', so values like '.', '..', '...' would pass,\n    # and as a path component they traverse the parent directory. Reject any\n    # value that's only dots.\n    if set(value) == {\".\"}:\n        raise ValueError(f\"ticker cannot consist solely of dots: {value!r}\")\n    return value\n\n\ndef save_output(data: pd.DataFrame, tag: str, save_path: SavePathType = None) -> None:\n    if save_path:\n        data.to_csv(save_path, encoding=\"utf-8\")\n        print(f\"{tag} saved to {save_path}\")","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/TauricResearch/TradingAgents/blob/a33fd4c0f134485a43553a2c23a63cb14adbd88f/tradingagents/dataflows/utils.py#L12-L48","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a concrete non-empty string ticker, e.g. 'AAPL'","Guard Optionals at the boundary: if not ticker: raise/return before calling","Coerce numeric ids to str at ingestion and validate they look like tickers"],"exampleFix":"# before\nsafe_ticker_component(None)      # or \"\" or 42\n# -> ValueError: ticker must be a non-empty string, got None\n\n# after\nif not isinstance(ticker, str) or not ticker:\n    raise ValueError(\"ticker required\")\nsafe_ticker_component(ticker)","handlingStrategy":"type-guard","validationCode":"def require_ticker(value) -> str:\n    if not isinstance(value, str) or not value.strip():\n        raise ValueError(f\"ticker required, got {value!r}\")\n    return value.strip()","typeGuard":"def is_nonempty_str(v) -> bool:\n    return isinstance(v, str) and v != \"\"","tryCatchPattern":"try:\n    safe_ticker_component(ticker)\nexcept ValueError as e:\n    if \"non-empty string\" in str(e):\n        ticker = \"SPY\"  # or reject the tool call / re-prompt the LLM\n    else:\n        raise","preventionTips":["Make ticker required (non-optional) in tool schemas given to LLMs","Resolve Optional fields at the boundary; never let None flow into data paths","Coerce numeric identifiers to str with validation at ingestion"],"tags":["validation","security","path-traversal","type-guard","symbols"],"backgroundTag":null,"analyzedSha":"a33fd4c0f134485a43553a2c23a63cb14adbd88f","analyzedAt":"2026-08-14T19:45:16.920Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}