Panniantong/Agent-Reach · error · GitHubConfigError
gh hosts.yml 顶层必须是对象
Error message
gh hosts.yml 顶层必须是对象
What it means
Raised when yaml.safe_load() succeeds but the top-level YAML value is not a mapping — e.g. the file contains a plain scalar, a list, or a multi-document stream whose first node is not a dict. gh's hosts.yml must be a map keyed by hostname.
Source
Thrown at agent_reach/channels/github.py:70
"""Inspect github.com's hosts.yml entry without executing gh."""
hosts_path = _gh_hosts_path()
try:
raw = read_small_text_no_follow(
hosts_path,
max_bytes=_MAX_HOSTS_BYTES,
)
except (OSError, PrivatePathError, UnicodeError) as exc:
raise GitHubConfigError("gh hosts.yml 无法安全读取") from exc
if raw is None:
return False
try:
payload = yaml.safe_load(raw)
except yaml.YAMLError as exc:
raise GitHubConfigError("gh hosts.yml 不是有效的 UTF-8 YAML") from exc
if payload is None:
return False
if not isinstance(payload, dict):
raise GitHubConfigError("gh hosts.yml 顶层必须是对象")
host = payload.get("github.com")
if host is None:
return False
if not isinstance(host, dict):
raise GitHubConfigError("gh hosts.yml 的 github.com 配置无效")
users = host.get("users")
if users is not None and not isinstance(users, dict):
raise GitHubConfigError("gh hosts.yml 的 users 配置无效")
return bool(host.get("oauth_token") or host.get("user") or users)
def _explicit_github_credentials(config) -> bool:
if any(os.environ.get(name) for name in ("GH_TOKEN", "GITHUB_TOKEN")):
return True
if config is None:
return FalseView on GitHub (pinned to 93ae1d18c3)
Solutions
- Rewrite hosts.yml to the correct shape: a top-level mapping with hostname keys (github.com: {oauth_token: ..., user: ...})
- Prefer `gh auth login` over hand-editing
- If YAML anchors/double documents are used, flatten to a single mapping document
Example fix
# before gho_abc123... # after github.com: oauth_token: gho_abc123... user: myname
Defensive patterns
Strategy: validation
Validate before calling
import yaml
def hosts_toplevel_is_map(path) -> bool:
try:
payload = yaml.safe_load(open(path, encoding="utf-8").read())
except Exception:
return False
return payload is None or isinstance(payload, dict) Try / catch
try:
_saved_github_host_configured()
except GitHubConfigError:
treat_github_as_unconfigured() Prevention
- hosts.yml top level must be hostname-keyed mappings only
- Never `echo token > hosts.yml`; use gh auth login
- After templating config, assert the rendered doc is a dict
When it happens
Trigger: hosts.yml contains just a token string ('gho_xxx'), a YAML list ('- github.com'), or '---\njust some text'. safe_load returns str/list, isinstance(payload, dict) fails, error raised. Note: empty file → payload is None → returns False (no error).
Common situations: Users echo a raw token into hosts.yml instead of using gh auth login; a template placeholder like '${TOKEN}' left unreplaced yields a scalar; accidental shell redirect truncation to a stray word.
Related errors
- gh hosts.yml 不是有效的 UTF-8 YAML
- gh hosts.yml 的 github.com 配置无效
- gh hosts.yml 的 users 配置无效
- gh hosts.yml 无法安全读取
- Agent Reach 的 GitHub 配置无法读取
AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14).
Data as JSON: /api/errors/49d327e25720a6de.
Report an issue: GitHub.