headroomlabs-ai/headroom · error · ValueError
Copilot OAuth token must not be empty.
Error message
Copilot OAuth token must not be empty.
What it means
save_headroom_copilot_oauth_token() strips the incoming token and raises ValueError if nothing remains. This is the persistence step for the token returned by GitHub's device login flow, and the guard prevents writing an auth file whose 'refresh' field is an empty string — which would later be silently unusable. The file (under headroom_copilot_auth_path()) is only written after the check plus a parent mkdir.
Source
Thrown at headroom/copilot_auth.py:499
logger.debug("Unable to read Headroom Copilot auth file: %s", exc)
return None
if not isinstance(payload, dict) or payload.get("type") != "oauth":
return None
token = payload.get("refresh")
return token.strip() if isinstance(token, str) and token.strip() else None
def save_headroom_copilot_oauth_token(
token: str,
*,
domain: str = DEFAULT_GITHUB_HOST,
) -> Path:
"""Persist the Copilot OAuth token returned by GitHub device login."""
token = token.strip()
if not token:
raise ValueError("Copilot OAuth token must not be empty.")
path = headroom_copilot_auth_path()
path.parent.mkdir(parents=True, exist_ok=True)
body: dict[str, Any] = {
"type": "oauth",
"provider": "github-copilot",
"refresh": token,
"domain": _github_oauth_domain(domain),
"created_at": int(time.time()),
}
path.write_text(json.dumps(body, indent=2, sort_keys=True) + "\n", encoding="utf-8")
try:
path.chmod(0o600)
except OSError:
pass
return path
View on GitHub (pinned to 322425c43b)
Solutions
- Validate before saving: check `token and token.strip()` and surface a meaningful auth error to the user
- Trace where the token came from — usually poll_copilot_device_authorization returned successfully but the caller stored the wrong field
- Never persist empty credentials; re-run the device authorization flow to obtain a real token
Example fix
# before
token = payload.get("access_token") or ""
save_headroom_copilot_oauth_token(token) # ValueError
# after
token = (payload.get("access_token") or "").strip()
if not token:
raise RuntimeError("Device flow returned no access token")
save_headroom_copilot_oauth_token(token) Defensive patterns
Strategy: validation
Validate before calling
token = (token or "").strip()
if not token:
raise ValueError("Refusing to save empty Copilot OAuth token — re-run device login") Type guard
def is_valid_oauth_token(value: object) -> bool:
return isinstance(value, str) and len(value.strip()) > 0 Try / catch
try:
save_headroom_copilot_oauth_token(token)
except ValueError:
# empty credential: never retry with the same value; restart the device flow
raise RuntimeError("Device flow produced no token; restart authorization") Prevention
- Validate token presence at the extraction site, not at persistence
- Treat empty OAuth fields as an upstream contract change — log payload keys (never values)
- Never write auth files with empty/blank credential fields
When it happens
Trigger: Calling save_headroom_copilot_oauth_token(token) with an empty string, a whitespace-only string, or None coerced to str. In practice this happens when a caller passes an unvalidated value extracted from an OAuth payload where the token field was absent.
Common situations: Wiring a custom GitHub device-flow client and forwarding payload.get('access_token') (None) directly; copy-paste scripts that read a token from an env var that was never set (os.environ.get gives None or ''); upstream API change renaming the token field so extraction yields ''.
Related errors
- No GitHub Copilot OAuth token is available.
- GitHub device authorization returned an invalid response.
- GitHub device authorization expired.
- GitHub device authorization failed: {description}
- Copilot token exchange returned an empty token.
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/b699a5a4b3b633e7.
Report an issue: GitHub.