BigPizzaV3/CodexPlusPlus · error · ValueError
codex config must be an object
Error message
codex config must be an object
What it means
load_config reads the config.toml-shaped JSON file and requires the top-level `codex` key to be a JSON object. It fires when the user's config file has a `codex` entry that is a string, number, array, or null (explicit `{}` is fine), meaning the bridge cannot extract nested fields like codex.command/args/timeouts from it.
Solutions
- Open the config file and change the `codex` value to a JSON object, e.g. "codex": {"command": "codex", "args": ["app-server"]}.
- If `codex` is not needed, remove the key entirely — the code falls back to raw.get("codex") or {}.
- Validate the file with a JSON linter to ensure no quoting mistakes turned the object into a string.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at tools/codex-wechat/codex_wechat.py:119 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/fb87ac13e560bee7.
Report an issue: GitHub.
Appendix: source
Thrown at tools/codex-wechat/codex_wechat.py:119
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(
raw.get("allow_id_command_for_unauthorized", True)
),
poll_timeout_seconds=int(raw.get("poll_timeout_seconds", 35)),
retry_delay_seconds=int(raw.get("retry_delay_seconds", 2)),
backoff_delay_seconds=int(raw.get("backoff_delay_seconds", 30)),
max_consecutive_failures=int(raw.get("max_consecutive_failures", 3)),
max_reply_chars=int(raw.get("max_reply_chars", 1800)),
enable_typing=bool(raw.get("enable_typing", True)),View on GitHub (pinned to b1ed92e5e4)