{"record":{"id":"ff00367638ed828c","repo":"BigPizzaV3/CodexPlusPlus","slug":"path-must-contain-a-json-object","errorCode":null,"errorMessage":"{path} must contain a JSON object","messagePattern":"(.+?) must contain a JSON object","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/codex-wechat/codex_wechat.py","lineNumber":111,"sourceCode":"\n\ndef log(message: str) -> None:\n    line = f\"{time.strftime('[%Y-%m-%d %H:%M:%S]')} {message}\"\n    print(line, flush=True)\n    if LOG_FILE:\n        try:\n            LOG_FILE.parent.mkdir(parents=True, exist_ok=True)\n            with LOG_FILE.open(\"a\", encoding=\"utf-8\") as f:\n                f.write(line + \"\\n\")\n        except Exception:\n            pass\n\n\ndef load_json_file(path: Path) -> dict[str, Any]:\n    with path.open(\"r\", encoding=\"utf-8\") as f:\n        data = json.load(f)\n    if not isinstance(data, dict):\n        raise ValueError(f\"{path} must contain a JSON object\")\n    return data\n\n\ndef load_config(path: Path) -> BridgeConfig:\n    raw = load_json_file(path)\n    codex_raw = raw.get(\"codex\") or {}\n    if not isinstance(codex_raw, dict):\n        raise ValueError(\"codex config must be an object\")\n\n    cfg = BridgeConfig(\n        base_url=str(raw.get(\"base_url\") or ILINK_BASE_URL),\n        token=str(raw.get(\"token\") or \"\"),\n        account_id=str(raw.get(\"account_id\") or \"\"),\n        allow_all=bool(raw.get(\"allow_all\", False)),\n        allow_user_ids=set(str(x) for x in raw.get(\"allow_user_ids\") or []),\n        require_prefix=bool(raw.get(\"require_prefix\", True)),\n        prefix=str(raw.get(\"prefix\") or \"/codex\"),\n        allow_id_command_for_unauthorized=bool(","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/tools/codex-wechat/codex_wechat.py#L93-L129","documentation":"load_json_file in codex_wechat.py loads a JSON file and raises ValueError(f\"{path} must contain a JSON object\") when json.load returns anything other than a dict (list, string, number, null). Config and QR-login state files must be top-level JSON objects for the bridge to work.","triggerScenarios":"load_config(path) or qr_login(path) reads a file whose parsed JSON is a top-level array, scalar, or null — e.g. config.json containing `[...]`, an empty file (JSONDecodeError path aside, null results from 'null'), or a credentials/state file written by another tool as a list.","commonSituations":"Hand-edited config.json that became an array; a state file truncated or overwritten with a non-object value; copying an example config with the wrong top-level shape; a QR state file written by a different version of the tool.","solutions":["Edit the file so its top level is a JSON object, e.g. {\"codex\": {...}, ...}","Validate with `python -m json.tool <path>` and check the outermost braces","Regenerate the file with the tool's own save/login flow instead of hand-editing","If the file is empty or corrupt, delete it and let the bridge recreate defaults"],"exampleFix":"// before (config.json)\n[\"codex\", {\"base_url\": \"...\"}]\n// after\n{\"codex\": {\"base_url\": \"...\"}}","handlingStrategy":"validation","validationCode":"import json, pathlib\nraw = json.loads(pathlib.Path(p).read_text(encoding='utf-8'))\nif not isinstance(raw, dict): raise ValueError(f'{p} must contain a JSON object')","typeGuard":"def is_json_object(path: Path) -> bool:\n    try:\n        return isinstance(json.loads(path.read_text(encoding='utf-8')), dict)\n    except Exception:\n        return False","tryCatchPattern":"try:\n    cfg = load_config(path)\nexcept ValueError as e:\n    print(f'config invalid: {e}'); sys.exit(2)","preventionTips":["Validate config files with `python -m json.tool` after hand edits","Always keep a top-level object: {\"codex\": {...}}","Back up state files before editing; let the tool regenerate corrupted ones"],"tags":["python","json","config","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}