Panniantong/Agent-Reach · error · ValueError
xfetch 会话文件必须是 JSON object
Error message
xfetch 会话文件必须是 JSON object
What it means
Raised in agent_reach/cookie_extract.py when the xfetch session file (~/.config/xfetch/session.json, capped at 64 KiB by _MAX_XFETCH_SESSION_BYTES) parses as valid JSON but is not an object — e.g. it is a list, string, or number. The loader (used for legacy xreach compatibility) requires a top-level JSON object mapping config keys to values. Message 'xfetch 会话文件必须是 JSON object' means 'the xfetch session file must be a JSON object'.
Source
Thrown at agent_reach/cookie_extract.py:348
return results
def _read_xfetch_session(path: Path) -> dict:
"""Read a small regular legacy session file without following symlinks."""
import json
from agent_reach.utils.paths import read_small_text_no_follow
payload = read_small_text_no_follow(
path,
max_bytes=_MAX_XFETCH_SESSION_BYTES,
)
if payload is None:
return {}
loaded = json.loads(payload)
if not isinstance(loaded, dict):
raise ValueError("xfetch 会话文件必须是 JSON object")
return loaded
def _sync_xfetch_session(auth_token: str, ct0: str) -> bool:
"""Sync Twitter credentials to ~/.config/xfetch/session.json (legacy xreach compat)."""
import json
try:
from agent_reach.utils.paths import (
atomic_write_private_text,
home_dir,
make_private_dir,
)
xfetch_dir = home_dir() / ".config" / "xfetch"
make_private_dir(xfetch_dir)
session_path = Path(xfetch_dir) / "session.json"
session_data = _read_xfetch_session(session_path)View on GitHub (pinned to 93ae1d18c3)
Solutions
- Rewrite ~/.config/xfetch/session.json so the top level is an object, e.g. {"twitter_auth_token": "...", "twitter_ct0": "..."}
- Validate with: python -c "import json;print(type(json.load(open('<path>'))))" — it must print <class 'dict'>
- If the file is expendable, delete it and let agent-reach regenerate it via _sync_xfetch_session
Example fix
// before: ~/.config/xfetch/session.json
[ {"twitter_auth_token": "a", "twitter_ct0": "b"} ]
// after
{ "twitter_auth_token": "a", "twitter_ct0": "b" } Defensive patterns
Strategy: type-guard
Validate before calling
import json
data = json.loads(Path('~/.config/xfetch/session.json').expanduser().read_text())
if not isinstance(data, dict):
raise ValueError('session.json must hold a JSON object') Type guard
def is_valid_session_file(path) -> bool:
try:
return isinstance(json.loads(Path(path).read_text()), dict)
except (OSError, json.JSONDecodeError):
return False Try / catch
try:
session = _load_xfetch_session(path)
except ValueError as e:
if 'JSON object' in str(e):
Path(path).unlink(missing_ok=True) # regenerate from config
else:
raise Prevention
- Never hand-edit session.json into a list
- Let _sync_xfetch_session own writes to that file
- Validate the file after any tool touches it
When it happens
Trigger: A hand-edited or tool-written session.json whose top level is a JSON array or scalar; migrating from a tool that serializes sessions as [ {...} ].
Common situations: Users editing session.json manually and wrapping it in a list; another tool overwriting the file with a different schema; truncated/rewritten exports.
Related errors
- mcporter 配置缺少 mcpServers 对象
- mcporter 配置包含无效的 server name
- mcporter server 定义必须是对象
- mcporter imports 必须是字符串列表
- mcporter 配置不是有效的 UTF-8 JSON
AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14).
Data as JSON: /api/errors/ebb5de4c0cd4a37e.
Report an issue: GitHub.