{"record":{"id":"7a594e6bfdc03686","repo":"TauricResearch/TradingAgents","slug":"ticker-cannot-consist-solely-of-dots-value-r","errorCode":null,"errorMessage":"ticker cannot consist solely of dots: {value!r}","messagePattern":"ticker cannot consist solely of dots: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tradingagents/dataflows/utils.py","lineNumber":41,"sourceCode":"    ``\"../../../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}\")\n\n\ndef get_current_date():\n    return date.today().strftime(\"%Y-%m-%d\")\n\n\ndef decorate_all_methods(decorator):\n    def class_decorator(cls):\n        for attr_name, attr_value in cls.__dict__.items():\n            if callable(attr_value):\n                setattr(cls, attr_name, decorator(attr_value))","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/TauricResearch/TradingAgents/blob/a33fd4c0f134485a43553a2c23a63cb14adbd88f/tradingagents/dataflows/utils.py#L23-L59","documentation":"Raised by ticker validation in tradingagents/dataflows/utils.py when a ticker symbol passed to the data layer consists only of dot characters ('.', '..', '...'). The filesystem-path regex allows dots, but a dots-only component would traverse the parent directory when the ticker is used to build cache/report file paths, so it is rejected explicitly. This is a guard against path traversal disguised as a symbol.","triggerScenarios":"Calling any dataflow function (e.g. get_YFinData / normalize-dependent helpers) with a ticker whose characters are all '.', such as ticker='.' or ticker='..'. The earlier regex check passes because '.' is an allowed path character, and this final check catches the traversal case.","commonSituations":"User-typed input parsed straight into a ticker field; CLI or LLM-produced arguments containing '.' or '..'; test fixtures with placeholder symbols; strings accidentally truncated to dots.","solutions":["Validate/normalize the ticker before calling the data API — strip whitespace and reject dots-only values.","Check the symbol against a whitelist pattern (letters, digits, '-', '.', '^') and require at least one non-dot character.","If the value came from user input, surface a clear form/CLI error instead of passing it downstream."],"exampleFix":"// before\nget_YFinData(start_date, end_date, ticker='..')\n\n// after\nfrom tradingagents.dataflows.utils import normalize_symbol\nticker = normalize_symbol('NVDA')  # validate first, avoid '.' / '..' inputs\nget_YFinData(start_date, end_date, ticker)","handlingStrategy":"validation","validationCode":"import re\n\ndef is_valid_ticker(value: str) -> bool:\n    return (\n        isinstance(value, str)\n        and value\n        and set(value) != {'.'}\n        and re.fullmatch(r'[A-Za-z0-9.^\\-]+', value) is not None\n    )\n\nassert is_valid_ticker('NVDA') and not is_valid_ticker('..')","typeGuard":"def is_safe_ticker(value: unknown) -> value is string:\n  return typeof value === 'string' && value.length > 0 && /[A-Za-z0-9.^-]/.test(value) && ![...value].every(c => c === '.')","tryCatchPattern":"try:\n    data = get_YFin_data_window(start, end, ticker)\nexcept ValueError as e:\n    if 'ticker' in str(e):\n        return handle_invalid_ticker(ticker)  # report to caller, do not retry\n    raise","preventionTips":["Validate ticker strings at the boundary where user/LLM input enters your app.","Treat dots-only values as hostile path input, not just bad symbols.","Centralize symbol validation in one helper used by every data call."],"tags":["validation","path-traversal","ticker","input-validation"],"backgroundTag":null,"analyzedSha":"a33fd4c0f134485a43553a2c23a63cb14adbd88f","analyzedAt":"2026-08-14T19:45:16.920Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}