HKUDS/Vibe-Trading · error · ValueError
start_date {start} must be before end_date {end}
Error message
start_date {start} must be before end_date {end} What it means
Raised by PortfolioRiskTool._parse_dates when the resolved start date is on or after the end date. The end date comes from end_raw (parsed as %Y-%m-%d); the start is either the supplied start_raw or end minus _DEFAULT_LOOKBACK_DAYS. The tool needs a strictly positive, ordered window to compute returns.
Source
Thrown at agent/src/tools/portfolio_risk_tool.py:161
missing = [sym for sym in symbols if sym not in raw]
if missing:
raise ValueError(f"weights missing basket symbols: {sorted(missing)}")
return {sym: raw[sym] for sym in symbols}
@staticmethod
def _parse_dates(start_raw: Any, end_raw: Any) -> tuple[str, str]:
end = (
datetime.strptime(end_raw, "%Y-%m-%d").date()
if isinstance(end_raw, str) and end_raw
else datetime.now(timezone.utc).date()
)
start = (
datetime.strptime(start_raw, "%Y-%m-%d").date()
if isinstance(start_raw, str) and start_raw
else end - timedelta(days=_DEFAULT_LOOKBACK_DAYS)
)
if start >= end:
raise ValueError(f"start_date {start} must be before end_date {end}")
return start.isoformat(), end.isoformat()
@staticmethod
def _closes_frame(raw: Mapping[str, Any], symbols: list[str]) -> pd.DataFrame:
"""Shape the fetch envelope into a date-indexed close-price panel."""
series: dict[str, pd.Series] = {}
for sym in symbols:
records = raw.get(sym)
if not records:
continue
times: list[Any] = []
prices: list[float] = []
for record in records:
if not isinstance(record, Mapping) or "close" not in record:
continue
when = next((record[k] for k in _DATE_KEYS if k in record), None)
try:
price = float(record["close"])View on GitHub (pinned to 80ffdda44c)
Solutions
- Ensure start_date is strictly earlier than end_date (equality is rejected)
- If you only have an end date, omit start_date so the default lookback is applied
- Verify both dates are ISO strings in YYYY-MM-DD format
- Swap the arguments if you accidentally passed them in reverse order
Example fix
# before start_date='2024-06-30', end_date='2024-06-30' # after start_date='2024-06-29', end_date='2024-06-30'
Defensive patterns
Strategy: validation
Validate before calling
from datetime import date, timedelta
end = date.fromisoformat(end_date)
start = date.fromisoformat(start_date) if start_date else end - timedelta(days=90)
if start >= end:
start = end - timedelta(days=1) # or raise for the caller to fix Type guard
def valid_date_range(start: str | None, end: str) -> bool:
try:
e = datetime.strptime(end, "%Y-%m-%d").date()
s = datetime.strptime(start, "%Y-%m-%d").date() if start else e - timedelta(days=90)
return s < e
except ValueError:
return False Try / catch
try:
result = tool.run(start_date=start, end_date=end)
except ValueError as e:
if "must be before" in str(e):
start, end = min(start, end), max(start, end) # auto-swap and retry Prevention
- Always pass dates as YYYY-MM-DD strings
- Omit start_date when the default lookback window is acceptable
- Assert start < end at the call site before invoking the tool
When it happens
Trigger: Passing start_date equal to end_date (start >= end triggers on equality), or start_date after end_date. Also occurs if dates are swapped (start later than end), or if unparseable date strings silently fall back to the default lookback and collide with end.
Common situations: Users swapping from/to parameters; same-day requests; timezone or off-by-one issues when generating date windows around 'today'; passing timestamps instead of YYYY-MM-DD strings.
Related errors
- maturity_date {self.maturity_date} precedes inception_date {
- start_date ({start}) > end_date ({end})
- start_date must be on or before end_date
- symbols must be a non-empty list of strings
- too many symbols ({len(symbols)}); cap is {_MAX_SYMBOLS}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/09caf7687096f6ff.
Report an issue: GitHub.