HKUDS/Vibe-Trading · error · ValueError

agent config 'channels' must be an object

Error message

agent config 'channels' must be an object

What it means

When persisting Feishu credentials, the loader expects the top-level 'channels' key in agent.json to be a JSON object. If it exists as an array, string, or number, a ValueError is raised rather than corrupting the config.

Source

Thrown at agent/src/channels/feishu.py:71

    same-directory temporary file and atomically replace the config so readers
    never observe a partial credential record.
    """
    from src.config.loader import _read_config_file
    from src.config.paths import get_config_path

    path = config_path or get_config_path()
    if path.suffix.lower() != ".json":
        raise ValueError(
            "Feishu QR login requires a JSON agent config; use "
            "~/.vibe-trading/agent.json"
        )

    payload: dict[str, Any] = {}
    if path.exists():
        payload = _read_config_file(path)
    channels = payload.setdefault("channels", {})
    if not isinstance(channels, dict):
        raise ValueError("agent config 'channels' must be an object")
    section = channels.setdefault("feishu", {})
    if not isinstance(section, dict):
        raise ValueError("agent config 'channels.feishu' must be an object")
    section.update(
        {
            "enabled": True,
            "app_id": app_id,
            "app_secret": app_secret,
            "domain": domain,
        }
    )

    path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
    content = (json.dumps(payload, ensure_ascii=False, indent=2) + "\n").encode("utf-8")
    fd, temporary = tempfile.mkstemp(
        dir=path.parent,
        prefix=f".{path.name}.",
        suffix=".tmp",

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Edit ~/.vibe-trading/agent.json and make channels an object: "channels": {}
  2. Move any channel entries under object keys, e.g. {"channels": {"feishu": {...}}}
  3. Validate the config with a JSON schema check before rerunning login

Example fix

// before
"channels": ["feishu"]
// after
"channels": {"feishu": {"enabled": true}}
Defensive patterns

Strategy: type-guard

Validate before calling

cfg = json.loads(open(cfg_path).read())
if 'channels' in cfg and not isinstance(cfg['channels'], dict): raise ValueError('channels must be an object')

Type guard

def has_valid_channels(cfg: dict) -> bool:
    return 'channels' not in cfg or isinstance(cfg['channels'], dict)

Prevention

When it happens

Trigger: agent.json contains "channels": [...] or "channels": "feishu" (any non-object), then QR login writes credentials.

Common situations: Hand-edited config mistakes, merging configs from examples that used a different schema, or a previous tool writing channels as a list of names.

Related errors


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