Panniantong/Agent-Reach · error · GitHubConfigError
gh hosts.yml 无法安全读取
Error message
gh hosts.yml 无法安全读取
What it means
Raised by _saved_github_host_configured() when the gh CLI's ~/.config/gh/hosts.yml cannot be safely read. Reading goes through read_small_text_no_follow(), which refuses symlinked path components, non-regular files, files over _MAX_HOSTS_BYTES, and raises OSError/UnicodeError for other I/O or UTF-8 decode failures. Any of these makes the GitHub channel's credential probe fail closed with GitHubConfigError.
Source
Thrown at agent_reach/channels/github.py:60
if os.name == "nt":
app_data = os.environ.get("APPDATA")
if app_data:
return Path(app_data) / "GitHub CLI" / "hosts.yml"
return Path.home() / ".config" / "gh" / "hosts.yml"
def _saved_github_host_configured() -> bool:
"""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")View on GitHub (pinned to 93ae1d18c3)
Solutions
- Inspect ~/.config/gh/hosts.yml: ensure it is a real file with no symlinks in its path (ls -la ~/.config/gh/) and replace symlinks with real files or bind mounts
- Check permissions: chmod 600 ~/.config/gh/hosts.yml and confirm you own it
- If the file is corrupt, run `gh auth login` again to regenerate a clean hosts.yml
- If you auth via token instead, export GH_TOKEN or GITHUB_TOKEN — _explicit_github_credentials() is checked before this path is relied on
- As a last resort remove hosts.yml; read returns None and the check reports 'not configured' instead of raising
Example fix
# before: ~/.config/gh/hosts.yml is a symlink to ~/dotfiles/gh-hosts.yml # after: real file cp ~/dotfiles/gh-hosts.yml ~/.config/gh/hosts.yml && chmod 600 ~/.config/gh/hosts.yml
Defensive patterns
Strategy: try-catch
Validate before calling
from pathlib import Path
import os
def hosts_readable() -> bool:
p = Path.home() / ".config" / "gh" / "hosts.yml"
if not p.exists() or p.is_symlink() or p.parent.is_symlink():
return False
try:
st = p.stat()
return st.st_size <= 64 * 1024 and os.access(p, os.R_OK)
except OSError:
return False Try / catch
from agent_reach.channels.github import GitHubConfigError
try:
configured = _saved_github_host_configured()
except GitHubConfigError as exc:
# degrade to 'not configured', surface hint to re-run gh auth login
report_config_hint(str(exc))
else:
use(configured) Prevention
- Never symlink gh config paths; keep ~/.config/gh as a real directory
- Run `gh auth login` instead of hand-writing hosts.yml
- Set GH_TOKEN/GITHUB_TOKEN so the env-var path short-circuits the file probe
When it happens
Trigger: Calling GitHubChannel.check()/doctor when: hosts.yml is a symlink or sits on a symlinked directory; the file is larger than _MAX_HOSTS_BYTES; the file is a FIFO/device; permissions deny read (OSError/EPERM); or the file contains bytes that are not valid UTF-8 (UnicodeError).
Common situations: Users manage dotfiles via symlinks (stow, chezmoi) so ~/.config/gh or hosts.yml is a link; hosts.yml got truncated/corrupted; disk-full or permission changes after a system migration; a non-UTF-8 editor wrote the file.
Related errors
- gh hosts.yml 不是有效的 UTF-8 YAML
- gh hosts.yml 顶层必须是对象
- gh hosts.yml 的 github.com 配置无效
- gh hosts.yml 的 users 配置无效
- mcporter 配置文件无法安全读取:{exc}
AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14).
Data as JSON: /api/errors/a95b37f661602c8e.
Report an issue: GitHub.