HKUDS/Vibe-Trading · error · ValueError
valuations[{index}] must be a (date, value) pair, got {type(
Error message
valuations[{index}] must be a (date, value) pair, got {type(item).__name__} What it means
The performance return functions (time_weighted_return, modified_dietz_return, money_weighted_return) normalise a valuations iterable into (date, value) pairs. Each element must be a two-element sequence; passing a bare string/bytes or a non-sequence scalar at some index raises this error naming the index and the offending Python type.
Source
Thrown at agent/src/quantlib/performance.py:308
``src.entities.models.normalize_date``, so ISO-8601 strings and
``datetime`` instances are accepted.
Returns:
Pairs sorted by date, with at least two entries.
Raises:
ValueError: If fewer than two valuations were supplied, a pair is
malformed, a value is not finite, or a date repeats. A repeated
date is rejected rather than deduplicated because two different
marks for one day have no defensible ordering.
"""
if isinstance(valuations, Mapping):
raw_items: list[tuple[object, object]] = list(valuations.items())
else:
raw_items = []
for index, item in enumerate(valuations):
if isinstance(item, (str, bytes)) or not isinstance(item, Sequence):
raise ValueError(
f"valuations[{index}] must be a (date, value) pair, got "
f"{type(item).__name__}"
)
pair = tuple(item)
if len(pair) != 2:
raise ValueError(
f"valuations[{index}] must have exactly two elements "
f"(date, value), got {len(pair)}"
)
raw_items.append((pair[0], pair[1]))
if len(raw_items) < 2:
raise ValueError(
"a return needs an opening and a closing valuation; got "
f"{len(raw_items)}"
)
resolved: list[tuple[date, float]] = []View on GitHub (pinned to 80ffdda44c)
Solutions
- Build pairs with zip: list(zip(dates, values)).
- If you meant a mapping input, pass {'2024-01-01': 100.0, ...} which is supported.
- Validate each element with isinstance(item, (tuple, list)) and len == 2 before calling.
Example fix
# before
twr = time_weighted_return(['2024-01-01', '2024-06-30', '2024-12-31']) # raises
# after
twr = time_weighted_return([('2024-01-01', 100.0), ('2024-12-31', 105.0)]) Defensive patterns
Strategy: type-guard
Validate before calling
vals = list(zip(dates, values)) # ensure pairs before calling assert all(isinstance(p, (tuple, list)) and len(p) == 2 for p in vals)
Type guard
from collections.abc import Sequence
def are_date_value_pairs(v) -> bool:
return all(
isinstance(i, Sequence) and not isinstance(i, (str, bytes)) and len(tuple(i)) == 2
for i in v
) Try / catch
try:
r = time_weighted_return(valuations)
except ValueError as e:
if 'must be a (date, value) pair' in str(e):
raise DataShapeError('valuations not paired') from e
raise Prevention
- Always construct valuations with zip(dates, values) or pass a Mapping.
- Never hand-build flat interleaved lists.
- Add a shape check in data prep.
When it happens
Trigger: Calling time_weighted_return(['2024-01-01', '2024-12-31']) — a list of date strings instead of pairs; or [date(2024,1,1), 100.0, date(2024,12,31), 105.0] with interleaved flat values; strings are explicitly rejected so they are not expanded character-by-character.
Common situations: Reading a CSV row of alternating dates and values into a flat list; forgetting zip(dates, values); mixing a Mapping for some periods and flat lists for others in user input.
Related errors
- valuations[{index}] must have exactly two elements (date, va
- a return needs an opening and a closing valuation; got {len(
- valuation on {when} must be numeric, got {raw_value!r}
- valuation on {when} must be finite, got {raw_value!r}; a mis
- {model}: {name} must be a finite number, got {val!r}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/97323f5ae81da216.
Report an issue: GitHub.