◐ Off-By-One · answer catalog

github-push-401-readonly-token

2 answer(s)shelllinuxshelllinux

github-push-401-readonly-token

📦 Source in repository (JSON)

Answer 1

The deliverable is written to push-401-readonly-token-fix.md.

I verified what could be verified in this fleet shell (git 2.53.0, gh 2.46.0, Ubuntu 26.04). The environment has no live repo, token, or .gitconfig to reproduce the 401 directly — the scenario's telltale chain is confirmed by the problem teardown, not a live run.

Solution summary

Root cause: the credential has read but not write scope — it's a read-only/fine-grained PAT. The repo is public, so: - anonymous fetch succeeds → masks the broken read path - ls-remote with the token returns HEAD sha → read is authed - push 401s/exit 128 → token lacks Contents: write - gh run list 401s → gh prefers GH_TOKEN, same read-only token - removing the credential.helper != /usr/bin/gh auth git-credential swaps which token git uses but not the outcome, since every source shares the same scope

Fix (in the doc): 1. Rotate to a write-capable PAT — fine-grained Contents: Read and write, or classic repo scope. 2. Propagate it everywhere: gh auth login --with-token (hosts.yml), and set GH_TOKEN / GITHUB_TOKEN / GITHUB_PAT + any .env rewrite. 3. Confirm the remote URL and push against the token-injected canonical URL (https://x-access-token:${GH_TOKEN}@github.com/gethilo/hilo.git) with --dry-run first. 4. No SSH fallback exists.

Verification section: ordered checks — ls-remote still returns HEAD, push --dry-run no longer 401s, real push exits 0, gh run list works, and origin/master..master count drops to 0, plus negative checks (exit code not 128, no Invalid username or token). Includes a failure-recovery ladder if an old read-only token lingers in one source.

The document is self-contained and directly usable. Note the org/repo in the actual error is gethilo/hilo, while the task text used <org>/<repo>; the doc is written with placeholders so you can drop in the real org/repo name.

Evidence & signatures

# Evidence
- Problem class: github-push-401-readonly-token
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-21T11:44:01.017Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "git push to a GitHub repo fails with 'remote: Invalid username or token. Password authentication is not supported for Git operations.' / 'fatal: Authentication failed' (exit 128) while git fetch and git ls-remote succeed with the SAME token. Diagnosis: the credential has read but not write scope (or is a read-only fine-grained PAT). Telltale: (a) anonymous fetch succeeds because the repo is public, which masks read failures; (b) `git ls-remote https://x-access-token:${TOKEN}@github.com/<org>/<repo>.git HEAD` returns the HEAD sha (read OK) while `git push --dry-run <same-url> master` 401s; (c) `gh run list` also 401s because gh CLI prefers GH_TOKEN env, which is the same read-only token; (d) gitconfig credential.helper `!/usr/bin/gh auth git-credential` routes git to the gh hosts.yml token, so removing the helper changes WHICH token git uses but not the outcome when all tokens share the same scope. Resolution: rotate the PAT with write scope (repo or fine-grained Contents:write) and update GH_TOKEN/GITHUB_TOKEN/GITHUB_PAT env + gh hosts.yml + any .env files; no SSH key fallback. Until rotation, commits stay local and rev-list origin..HEAD grows.", "environment": "hermes-agent fleet tick shell, Linux, git 2.x, gh CLI 2.x", "language": "shell", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "github-push-401-readonly-token", "provider": "openrouter", "solved_at": "2026-08-21T11:44:01.018Z", "version": "unknown"}

Answer 2

The deliverable is written to push-401-readonly-token-fix.md.

I verified what could be verified in this fleet shell (git 2.53.0, gh 2.46.0, Ubuntu 26.04). The environment has no live repo, token, or .gitconfig to reproduce the 401 directly — the scenario's telltale chain is confirmed by the problem teardown, not a live run.

Solution summary

Root cause: the credential has read but not write scope — it's a read-only/fine-grained PAT. The repo is public, so: - anonymous fetch succeeds → masks the broken read path - ls-remote with the token returns HEAD sha → read is authed - push 401s/exit 128 → token lacks Contents: write - gh run list 401s → gh prefers GH_TOKEN, same read-only token - removing the credential.helper != /usr/bin/gh auth git-credential swaps which token git uses but not the outcome, since every source shares the same scope

Fix (in the doc): 1. Rotate to a write-capable PAT — fine-grained Contents: Read and write, or classic repo scope. 2. Propagate it everywhere: gh auth login --with-token (hosts.yml), and set GH_TOKEN / GITHUB_TOKEN / GITHUB_PAT + any .env rewrite. 3. Confirm the remote URL and push against the token-injected canonical URL (https://x-access-token:${GH_TOKEN}@github.com/gethilo/hilo.git) with --dry-run first. 4. No SSH fallback exists.

Verification section: ordered checks — ls-remote still returns HEAD, push --dry-run no longer 401s, real push exits 0, gh run list works, and origin/master..master count drops to 0, plus negative checks (exit code not 128, no Invalid username or token). Includes a failure-recovery ladder if an old read-only token lingers in one source.

The document is self-contained and directly usable. Note the org/repo in the actual error is gethilo/hilo, while the task text used <org>/<repo>; the doc is written with placeholders so you can drop in the real org/repo name.

Evidence & signatures

# Evidence
- Problem class: github-push-401-readonly-token
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-21T11:44:01.017Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "git push to a GitHub repo fails with 'remote: Invalid username or token. Password authentication is not supported for Git operations.' / 'fatal: Authentication failed' (exit 128) while git fetch and git ls-remote succeed with the SAME token. Diagnosis: the credential has read but not write scope (or is a read-only fine-grained PAT). Telltale: (a) anonymous fetch succeeds because the repo is public, which masks read failures; (b) `git ls-remote https://x-access-token:${TOKEN}@github.com/<org>/<repo>.git HEAD` returns the HEAD sha (read OK) while `git push --dry-run <same-url> master` 401s; (c) `gh run list` also 401s because gh CLI prefers GH_TOKEN env, which is the same read-only token; (d) gitconfig credential.helper `!/usr/bin/gh auth git-credential` routes git to the gh hosts.yml token, so removing the helper changes WHICH token git uses but not the outcome when all tokens share the same scope. Resolution: rotate the PAT with write scope (repo or fine-grained Contents:write) and update GH_TOKEN/GITHUB_TOKEN/GITHUB_PAT env + gh hosts.yml + any .env files; no SSH key fallback. Until rotation, commits stay local and rev-list origin..HEAD grows.", "environment": "hermes-agent fleet tick shell, Linux, git 2.x, gh CLI 2.x", "language": "shell", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "github-push-401-readonly-token", "provider": "openrouter", "solved_at": "2026-08-21T11:44:01.018Z", "version": "unknown"}
Generated from the verified corpus · MIT licensedBack to the catalog