HKUDS/Vibe-Trading · error · ValueError
flow_timing must be {FLOW_TIMING_END!r} or {FLOW_TIMING_STAR
Error message
flow_timing must be {FLOW_TIMING_END!r} or {FLOW_TIMING_START!r}, got {raw!r} What it means
The `flow_timing` option must be exactly one of the two recognized tokens (end or start), after stripping and lowercasing. Any other non-empty value is rejected because cashflow timing conventions change computed results (end-of-period vs start-of-period discounting).
Source
Thrown at agent/src/tools/cashflow_analytics_tool.py:420
def _coerce_flow_timing(raw: Any) -> str:
"""Validate the flow-timing token.
Args:
raw: Value supplied for ``flow_timing``; ``None`` selects the default.
Returns:
Either :data:`~src.quantlib.performance.FLOW_TIMING_END` or
:data:`~src.quantlib.performance.FLOW_TIMING_START`.
Raises:
ValueError: If the token is not one of the two recognised values.
"""
if raw is None or raw == "":
return FLOW_TIMING_END
token = str(raw).strip().lower()
if token not in (FLOW_TIMING_END, FLOW_TIMING_START):
raise ValueError(
f"flow_timing must be {FLOW_TIMING_END!r} or {FLOW_TIMING_START!r}, "
f"got {raw!r}"
)
return token
def _coerce_kinds(raw: Any, field_name: str) -> list[str] | None:
"""Validate an optional kind-classification override.
Args:
raw: Value supplied for ``external_kinds`` or ``internal_kinds``.
field_name: Name used in the error message.
Returns:
The list of labels, or ``None`` to keep the module default.
Raises:
ValueError: If the value is not an array of non-empty strings.View on GitHub (pinned to 80ffdda44c)
Solutions
- Set flow_timing to 'end' or 'start' (case-insensitive), or omit it / pass '' to default to 'end'
- If the value comes from user config, validate it against the allowed set before invoking the tool
Example fix
# before result = execute(flows=flows, flow_timing="beginning") # after result = execute(flows=flows, flow_timing="start") # 'beginning' maps to 'start'
Defensive patterns
Strategy: type-guard
Validate before calling
ALLOWED = {"end", "start"}
def norm_timing(v):
if v is None:
return "end"
t = str(v).strip().lower()
assert t in ALLOWED, f"flow_timing must be one of {ALLOWED}, got {v!r}"
return t Type guard
def is_flow_timing(v) -> bool:
return v is None or (isinstance(v, str) and (not v.strip() or v.strip().lower() in {"end", "start"})) Try / catch
try:
execute(flows=flows, flow_timing=timing)
except ValueError as exc:
if "flow_timing must be" in str(exc):
execute(flows=flows, flow_timing="end") # safe default
else:
raise Prevention
- Keep the allowed tokens ('end'/'start') in one constant reused by callers and UI validation
- Map external vocabulary (e.g. 'beginning'->'start') at your boundary
- Omit the argument entirely when the default end-of-period is acceptable
When it happens
Trigger: Passing flow_timing='beginning', 'END ' (ok, lowercased), 'middle', 'e', or an arbitrary string to the tool's execute(); only ''/None and the two exact tokens (case-insensitive) are accepted.
Common situations: Callers copy terminology from other finance libraries (e.g. numpy-financial's 'beginning'/'end'); LLM agents guess the enum; config files carry a stale token from an older version.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- amount must be a finite number, got {self.amount!r}; a missi
- kind={self.kind!r} must have a {direction} amount under the
- pre_translated=True asserts the flows were already converted
- start {lower} is after end {upper}
- unknown hypothesis status '{status}'. Allowed: {allowed}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/829b1de39184efab.
Report an issue: GitHub.