HKUDS/Vibe-Trading · error · TushareFallbackUnavailable

invalid date for tushare fallback: {value!r}

Error message

invalid date for tushare fallback: {value!r}

What it means

_compact_date normalizes a date string for Tushare's YYYYMMDD API format; it strips dashes then requires exactly 8 digits. It raises TushareFallbackUnavailable when the value doesn't reduce to 8 digits — for example '2024/01/05' (slashes survive), '2024-1-5' (only 6 digits), or arbitrary text like 'latest'.

Source

Thrown at agent/src/tools/tushare_fallbacks.py:49


def _records(frame: Any) -> list[dict[str, Any]]:
    if frame is None:
        return []
    if bool(getattr(frame, "empty", False)):
        return []
    if hasattr(frame, "to_dict"):
        rows = frame.to_dict("records")
        return [row for row in rows if isinstance(row, dict)]
    if isinstance(frame, list):
        return [row for row in frame if isinstance(row, dict)]
    return []


def _compact_date(value: str) -> str:
    digits = str(value).strip().replace("-", "")
    if len(digits) != 8 or not digits.isdigit():
        raise TushareFallbackUnavailable(f"invalid date for tushare fallback: {value!r}")
    return digits


def _dashed_date(value: Any) -> str | None:
    if value is None:
        return None
    digits = str(value).strip().replace("-", "")
    if len(digits) == 8 and digits.isdigit():
        return f"{digits[:4]}-{digits[4:6]}-{digits[6:]}"
    return str(value)[:10] if value else None


def _date_window(days: int) -> tuple[str, str]:
    end = date.today()
    # Market holidays/weekends mean calendar days need slack to recover the
    # requested number of trading rows.
    start = end - timedelta(days=max(days * 3, 10))
    return start.strftime("%Y%m%d"), end.strftime("%Y%m%d")

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Normalize the date to 'YYYY-MM-DD' or 'YYYYMMDD' before calling fetch_dragon_tiger
  2. Validate/parse user-supplied dates at the boundary (e.g. datetime.date.isoformat())
  3. Default missing dates to a computed trade date instead of passing raw input through
  4. Catch TushareFallbackUnavailable and surface a clear 'expected YYYY-MM-DD' message

Example fix

# before
fetch_dragon_tiger(trade_date="2024/06/01")

# after
from datetime import datetime
date = datetime.strptime("2024/06/01", "%Y/%m/%d").strftime("%Y-%m-%d")
fetch_dragon_tiger(trade_date=date)
Defensive patterns

Strategy: validation

Validate before calling

import re

def is_valid_trade_date(value: str) -> bool:
    digits = str(value).strip().replace('-', '')
    return bool(re.fullmatch(r'\d{8}', digits))

assert is_valid_trade_date(trade_date), f'bad date: {trade_date!r}'

Type guard

def is_iso_date(value: str) -> bool:
    """Type-level guard for 'YYYY-MM-DD' strings accepted by the fallback."""
    import re
    return isinstance(value, str) and bool(re.fullmatch(r'\d{4}-\d{2}-\d{2}|\d{8}', value))

Try / catch

try:
    rows = fetch_dragon_tiger(trade_date=raw)
except TushareFallbackUnavailable as exc:
    if 'invalid date' in str(exc):
        raise ValueError(f'expected YYYY-MM-DD, got {raw!r}') from exc
    raise

Prevention

When it happens

Trigger: fetch_dragon_tiger (and any caller of _compact_date) passing a date like '2024/06/01', '2024060', '202406011', 'today', or None coerced to the string 'None'. Only plain 'YYYY-MM-DD' or 'YYYYMMDD' forms pass.

Common situations: Dates sourced from user input or another API with a different format (slashes, abbreviated months); empty string defaults; a date already normalized by a different layer producing a non-8-digit result; timezone/locale-specific formatting.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/3875c465239b504c. Report an issue: GitHub.