HKUDS/Vibe-Trading · error · ValueError

{name} must be a string, got {value!r}

Error message

{name} must be a string, got {value!r}

What it means

strategy_discovery_tool._coerce_opt_str validates optional string parameters and requires them to actually be str instances — no implicit str() conversion is performed. Passing any non-string, non-None value (int, list, dict, bool) raises ValueError naming the parameter and the value. Empty/None are handled separately as absent.

Source

Thrown at agent/src/tools/strategy_discovery_tool.py:101

    if value is None:
        return None
    if isinstance(value, bool):
        raise ValueError(f"{name} must be a number, got {value!r}")
    try:
        result = float(value)
    except (TypeError, ValueError, OverflowError) as exc:
        raise ValueError(f"{name} must be a number, got {value!r}") from exc
    if result != result or result in (float("inf"), float("-inf")):
        raise ValueError(f"{name} must be a finite number, got {value!r}")
    return result


def _coerce_opt_str(value: Any, name: str) -> str | None:
    """Coerce an optional string parameter; blank/None become ``None``."""
    if value is None:
        return None
    if not isinstance(value, str):
        raise ValueError(f"{name} must be a string, got {value!r}")
    if len(value) > _MAX_STRING_PARAM_CHARS:
        raise ValueError(
            f"{name} is too long ({len(value)} chars; "
            f"max {_MAX_STRING_PARAM_CHARS})"
        )
    text = value.strip()
    return text or None


def _coerce_bool(value: Any, name: str, default: bool) -> bool:
    """Coerce a boolean parameter, tolerating common LLM string forms."""
    if value is None:
        return default
    if isinstance(value, bool):
        return value
    if isinstance(value, str):
        lowered = value.strip().lower()
        if lowered in {"true", "1", "yes"}:

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Convert the value to str yourself before passing: str(value) when appropriate
  2. Pass the correctly typed value (e.g. a string name, not a list)
  3. Omit the kwarg or pass None if the optional string isn't needed

Example fix

# before
tool.execute(universe=['SPY','QQQ'])
# after
tool.execute(universe="SPY,QQQ")  # or the documented string format
Defensive patterns

Strategy: type-guard

Validate before calling

if value is not None and not isinstance(value, str):
    value = str(value)
tool.execute(**{name: value})

Type guard

def is_str_arg(v) -> bool:
    return v is None or isinstance(v, str)

Prevention

When it happens

Trigger: Passing 123, ["a"], or True for a string parameter, e.g. execute(universe=500) where a ticker list string is expected; passing bytes is also rejected (not a str).

Common situations: LLM tool calls emitting JSON numbers/arrays for text fields; upstream code passing IDs as ints where the tool wants strings; bytes vs str confusion after deserialization.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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