OpenBMB/ChatDev · error · ValueError

package entries must be strings

Error message

package entries must be strings

What it means

install_python_packages validates every entry in its packages list and requires each to be a string. Non-string entries (None, numbers, lists/dicts from malformed JSON) raise ValueError before any uv command runs. This front-loads type validation so bad payloads fail fast.

Source

Thrown at functions/function_calling/uv_related.py:68

            raise ValueError("python_workspace_root missing from _context")
        path = Path(raw_path).expanduser().resolve()
        path.mkdir(parents=True, exist_ok=True)
        return path

    def resolve_under_workspace(self, relative_path: str | Path) -> Path:
        candidate = Path(relative_path)
        absolute = candidate if candidate.is_absolute() else self.workspace_root / candidate
        absolute = absolute.expanduser().resolve()
        if self.workspace_root not in absolute.parents and absolute != self.workspace_root:
            raise ValueError("script path is outside workspace root")
        return absolute


def _validate_packages(packages: Sequence[str]) -> List[str]:
    normalized: List[str] = []
    for pkg in packages:
        if not isinstance(pkg, str):
            raise ValueError("package entries must be strings")
        stripped = pkg.strip()
        if not stripped:
            raise ValueError("package names cannot be empty")
        if not _SAFE_PACKAGE_RE.match(stripped):
            raise ValueError(f"unsafe characters detected in package spec {pkg}")
        if stripped.startswith("-"):
            raise ValueError(f"flags are not allowed in packages list: {pkg}")
        normalized.append(stripped)
    if not normalized:
        raise ValueError("at least one package is required")
    return normalized


def _coerce_timeout_seconds(timeout_seconds: Any) -> float | None:
    if timeout_seconds is None:
        return None
    if isinstance(timeout_seconds, bool):
        raise ValueError("timeout_seconds must be a number")

View on GitHub (pinned to 4fb2db0ea9)

Solutions

  1. Ensure every packages entry is a str
  2. Validate/cast entries (e.g. str(p) only when sensible) before calling
  3. Add a JSON schema requiring items.type=string for the packages array in your tool definition

Example fix

# before
install_python_packages(packages=["numpy", 42])
# after
install_python_packages(packages=["numpy", "pydantic"])
Defensive patterns

Strategy: type-guard

Validate before calling

packages = [p for p in packages if isinstance(p, str) and p.strip()]
install_python_packages(packages=packages, _context=ctx)

Type guard

def all_strings(items) -> bool:
    return all(isinstance(i, str) for i in items)

Try / catch

try:
    install_python_packages(packages=packages, _context=ctx)
except ValueError as e:
    if "must be strings" in str(e):
        packages = [str(p) for p in packages if p]
        install_python_packages(packages=packages, _context=ctx)
    else:
        raise

Prevention

When it happens

Trigger: Passing packages=["numpy", 42] or packages=[None]; JSON tool args where an element is a number or nested object; unpacking a tuple/iterable of mixed types into the list.

Common situations: LLM tool-call payloads with mixed-type arrays; config files parsed without schema validation; programmatic lists built from untyped inputs.

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 OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27). Data as JSON: /api/errors/eb2f8b495064e4f6. Report an issue: GitHub.