BigPizzaV3/CodexPlusPlus · error · ValueError
must contain a JSON object
Error message
{path} must contain a JSON object What it means
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.
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
Example fix
// before (config.json)
["codex", {"base_url": "..."}]
// after
{"codex": {"base_url": "..."}} Defensive patterns
Strategy: validation
Validate before calling
import json, pathlib
raw = json.loads(pathlib.Path(p).read_text(encoding='utf-8'))
if not isinstance(raw, dict): raise ValueError(f'{p} must contain a JSON object') Type guard
def is_json_object(path: Path) -> bool:
try:
return isinstance(json.loads(path.read_text(encoding='utf-8')), dict)
except Exception:
return False Try / catch
try:
cfg = load_config(path)
except ValueError as e:
print(f'config invalid: {e}'); sys.exit(2) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- model_metadata 的模型 值必须是对象
- 官方混合 API 不应在 auth.json 中保存 OPENAI_API_KEY。请清理此供应商的…
- 请填写 API 的模型名称
- auth.json 必须是 JSON 对象
- Base URL 不能为空
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/ff00367638ed828c.
Report an issue: GitHub.
Appendix: source
Thrown at tools/codex-wechat/codex_wechat.py:111
def log(message: str) -> None:
line = f"{time.strftime('[%Y-%m-%d %H:%M:%S]')} {message}"
print(line, flush=True)
if LOG_FILE:
try:
LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
with LOG_FILE.open("a", encoding="utf-8") as f:
f.write(line + "\n")
except Exception:
pass
def load_json_file(path: Path) -> dict[str, Any]:
with path.open("r", encoding="utf-8") as f:
data = json.load(f)
if not isinstance(data, dict):
raise ValueError(f"{path} must contain a JSON object")
return data
def load_config(path: Path) -> BridgeConfig:
raw = load_json_file(path)
codex_raw = raw.get("codex") or {}
if not isinstance(codex_raw, dict):
raise ValueError("codex config must be an object")
cfg = BridgeConfig(
base_url=str(raw.get("base_url") or ILINK_BASE_URL),
token=str(raw.get("token") or ""),
account_id=str(raw.get("account_id") or ""),
allow_all=bool(raw.get("allow_all", False)),
allow_user_ids=set(str(x) for x in raw.get("allow_user_ids") or []),
require_prefix=bool(raw.get("require_prefix", True)),
prefix=str(raw.get("prefix") or "/codex"),
allow_id_command_for_unauthorized=bool(View on GitHub (pinned to b1ed92e5e4)