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

  1. Rewrite ~/.config/xfetch/session.json so the top level is an object, e.g. {"twitter_auth_token": "...", "twitter_ct0": "..."}
  2. Validate with: python -c "import json;print(type(json.load(open('<path>'))))" — it must print <class 'dict'>
  3. 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

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


AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14). Data as JSON: /api/errors/ebb5de4c0cd4a37e. Report an issue: GitHub.