HKUDS/Vibe-Trading · error · ValueError

unknown zoo {v!r}; expected one of {sorted(_VALID_ZOOS)}

Error message

unknown zoo {v!r}; expected one of {sorted(_VALID_ZOOS)}

What it means

load_adapter dynamically imports a user-installed local connector adapter module via importlib.util.spec_from_file_location. If the spec or its loader cannot be created — typically because plugin.module_path points to a file that no longer exists or is unreadable — a bare RuntimeError is raised with the profile id. It means the plugin manifest is registered but its module file can't be located/loaded.

Source

Thrown at agent/src/api/alpha_routes.py:164

# ---------------------------------------------------------------------------
# Request/response schemas
# ---------------------------------------------------------------------------


class BenchRequest(BaseModel):
    """POST /alpha/bench body."""

    zoo: str = Field(..., min_length=1, max_length=64)
    universe: str = Field(..., min_length=1, max_length=64)
    period: str = Field(..., min_length=4, max_length=32)
    top: int = Field(20, ge=1, le=500)

    @field_validator("zoo")
    @classmethod
    def _zoo_known(cls, v: str) -> str:
        if v not in _VALID_ZOOS:
            raise ValueError(
                f"unknown zoo {v!r}; expected one of {sorted(_VALID_ZOOS)}"
            )
        return v

    @field_validator("universe")
    @classmethod
    def _universe_known(cls, v: str) -> str:
        if v not in _BENCH_UNIVERSES:
            raise ValueError(
                f"unknown universe {v!r}; expected one of {sorted(_BENCH_UNIVERSES)}"
            )
        return v


class CompareRequest(BaseModel):
    """POST /alpha/compare body — a head-to-head of >= 2 named alphas."""

    alpha_ids: list[str] = Field(..., min_length=2, max_length=50)

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Verify the plugin's module_path file exists on disk (inspect the plugin registry/manifest) and restore or reinstall it
  2. Reinstall the connector with the install command, or uninstall the stale plugin entry so discovery stops returning it
  3. If the path is valid, check file permissions and that the path is a regular .py file

Example fix

# before: stale registry entry, file moved
plugin = plugin_by_profile_id(profile.id)
adapter = load_adapter(plugin)  # RuntimeError

# after: validate path before loading
from pathlib import Path
if not Path(plugin.module_path).is_file():
    raise FileNotFoundError(f"plugin module missing: {plugin.module_path}")
adapter = load_adapter(plugin)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def plugin_module_loadable(plugin) -> bool:
    p = Path(plugin.module_path)
    return p.is_file() and p.suffix == ".py" and os.access(p, os.R_OK)

Try / catch

try:
    adapter = load_adapter(plugin)
except RuntimeError as e:
    if "cannot load connector adapter" in str(e):
        uninstall_or_repair_plugin(plugin)  # restore module_path or drop entry
    raise

Prevention

When it happens

Trigger: Calling any read operation (check_connection, get_account, get_positions, etc.) through _local_plugin_call for a profile whose local plugin file was deleted, moved, or has wrong permissions after installation; a stale plugin registry entry whose module_path no longer resolves.

Common situations: User manually deleted or moved the connector directory under the plugin root, synced/cleaned the workspace, or the plugin was installed from a different machine/user with absolute paths that no longer hold.

Related errors


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