HKUDS/Vibe-Trading · error · ValueError

{field_name} must be a non-empty array of kind labels

Error message

{field_name} must be a non-empty array of kind labels

What it means

The filter fields accepted by _coerce_kinds (e.g. include_kinds/exclude_kinds) must be a non-empty list of strings when provided. An empty list, a scalar, a tuple, or any other non-list value is rejected because an empty filter is ambiguous (no filtering vs filter-everything).

Source

Thrown at agent/src/tools/cashflow_analytics_tool.py:443


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.
    """
    if raw is None:
        return None
    if not isinstance(raw, list) or not raw:
        raise ValueError(f"{field_name} must be a non-empty array of kind labels")
    labels: list[str] = []
    for item in raw:
        if not isinstance(item, str) or not item.strip():
            raise ValueError(f"{field_name} entries must be non-empty strings")
        labels.append(item)
    return labels


def _rounded(value: float) -> float:
    """Round a finite scalar for stable, compact JSON.

    Args:
        value: Number to round.

    Returns:
        The value rounded to :data:`_ROUNDING` decimal places.
    """
    return round(float(value), _ROUNDING)

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Pass None (or omit the argument) when no kind filtering is wanted
  2. Ensure the value is a Python list with at least one non-empty label string, e.g. ["dividend"]
  3. Coerce tuples/sets to list(...) before calling

Example fix

# before
execute(flows=flows, include_kinds=[])
# after
execute(flows=flows, include_kinds=None)
# or
execute(flows=flows, include_kinds=["coupon"])
Defensive patterns

Strategy: type-guard

Validate before calling

def norm_kinds(field_name, v):
    if v is None:
        return None
    if not isinstance(v, list) or not v:
        raise TypeError(f"{field_name} must be a non-empty list or None")
    return v

Type guard

def is_kinds_list(v) -> bool:
    return v is None or (isinstance(v, list) and len(v) > 0)

Try / catch

try:
    execute(flows=flows, include_kinds=kinds)
except ValueError as exc:
    if "must be a non-empty array" in str(exc):
        execute(flows=flows, include_kinds=None)  # drop the filter
    else:
        raise

Prevention

When it happens

Trigger: Passing include_kinds=[] (empty list), include_kinds="dividend" (bare string), or a tuple/set instead of a list; None is allowed and means 'no filter'.

Common situations: Dynamically building filters that end up empty after filtering; spreading a possibly-empty sequence from user input; assuming any iterable is accepted.

Related errors


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