{"record":{"id":"9e4e67fe9f3ff89e","repo":"HKUDS/Vibe-Trading","slug":"agent-config-channels-feishu-must-be-an-object","errorCode":null,"errorMessage":"agent config 'channels.feishu' must be an object","messagePattern":"agent config 'channels\\.feishu' must be an object","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/channels/feishu.py","lineNumber":74,"sourceCode":"    from src.config.loader import _read_config_file\n    from src.config.paths import get_config_path\n\n    path = config_path or get_config_path()\n    if path.suffix.lower() != \".json\":\n        raise ValueError(\n            \"Feishu QR login requires a JSON agent config; use \"\n            \"~/.vibe-trading/agent.json\"\n        )\n\n    payload: dict[str, Any] = {}\n    if path.exists():\n        payload = _read_config_file(path)\n    channels = payload.setdefault(\"channels\", {})\n    if not isinstance(channels, dict):\n        raise ValueError(\"agent config 'channels' must be an object\")\n    section = channels.setdefault(\"feishu\", {})\n    if not isinstance(section, dict):\n        raise ValueError(\"agent config 'channels.feishu' must be an object\")\n    section.update(\n        {\n            \"enabled\": True,\n            \"app_id\": app_id,\n            \"app_secret\": app_secret,\n            \"domain\": domain,\n        }\n    )\n\n    path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)\n    content = (json.dumps(payload, ensure_ascii=False, indent=2) + \"\\n\").encode(\"utf-8\")\n    fd, temporary = tempfile.mkstemp(\n        dir=path.parent,\n        prefix=f\".{path.name}.\",\n        suffix=\".tmp\",\n    )\n    try:\n        try:","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/channels/feishu.py#L56-L92","documentation":"Inside the channels object, the 'feishu' entry must itself be a JSON object so credentials (app_id, app_secret, domain) can be merged in. A non-object value triggers this ValueError instead of overwriting user data.","triggerScenarios":"agent.json has \"channels\": {\"feishu\": true} or \"feishu\": \"enabled\" — any non-object — when QR login persists credentials.","commonSituations":"Minimal hand-written configs that use booleans/strings as toggles for channels; copy-paste from older config examples with a flat schema.","solutions":["Change the entry to an object: \"channels\": {\"feishu\": {}} — login will fill in credentials","Remove the malformed feishu entry entirely and let setdefault recreate it as an object"],"exampleFix":"// before\n\"channels\": {\"feishu\": true}\n// after\n\"channels\": {\"feishu\": {\"enabled\": true}}","handlingStrategy":"type-guard","validationCode":"ch = cfg.setdefault('channels', {})\nif 'feishu' in ch and not isinstance(ch['feishu'], dict): raise ValueError('channels.feishu must be an object')","typeGuard":"def has_valid_feishu_section(cfg: dict) -> bool:\n    ch = cfg.get('channels', {})\n    return isinstance(ch, dict) and ('feishu' not in ch or isinstance(ch['feishu'], dict))","tryCatchPattern":null,"preventionTips":["Represent channel config as an object of settings, not a bool/string toggle"],"tags":["config","feishu","schema","json"],"backgroundTag":"config-schema-invalid","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}