Skip to content

Troubleshooting

Csaba Polyak edited this page Sep 28, 2026 · 1 revision

Troubleshooting

This page covers the most common problems encountered when running GitHub Mirror Backup.

The script performs several independent operations:

GitHub API
    ↓
Repository discovery
    ↓
SSH authentication
    ↓
Git mirror clone/update
    ↓
Local storage

The first step is therefore to identify which layer is failing.


SSH Authentication Errors

SSH is used to access the actual Git repositories.

Test it directly:

ssh -T git@github.com

A successful authentication looks similar to:

Hi USERNAME! You've successfully authenticated, but GitHub does not provide shell access.

This message is normal. GitHub does not provide shell access through this endpoint.

Permission denied (publickey)

Example:

git@github.com: Permission denied (publickey).

Check whether an SSH key exists:

ls -la ~/.ssh/

Check which keys SSH is attempting to use:

ssh -vT git@github.com

Look for lines containing:

Offering public key
Server accepts key

If necessary, explicitly configure the key in:

~/.ssh/config

Example:

Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Then test again:

ssh -T git@github.com

SSH key belongs to the wrong GitHub account

The script compares the GitHub account returned by the API with the account authenticated through SSH.

For example:

API account    csiber
SSH account    another-user

This produces a warning.

The SSH key may belong to a different GitHub account, so that account may not have access to all repositories discovered through the API token.

Fix the SSH key configuration or register the correct public key with the correct GitHub account.


Token / GitHub API Errors

The Personal Access Token is used for repository discovery.

Check that the token file exists:

ls -l ~/.config/github/token

Recommended permissions:

chmod 600 ~/.config/github/token

The token should contain one token on one line.

Test the API manually

curl -fsSL \
  -H "Authorization: Bearer $(cat ~/.config/github/token)" \
  -H "Accept: application/vnd.github+json" \
  https://api.github.com/user

A successful request returns JSON containing the authenticated account.

If the request returns an authentication error, check:

  • token is still valid
  • token has not expired
  • token has sufficient repository permissions
  • token belongs to the expected GitHub account

Invalid or expired token

Typical API response:

401 Unauthorized

Create a new token and replace the contents of:

~/.config/github/token

Then test the API again.

Do not put the new token into the script itself.

Repositories are missing

If the API works but some repositories are not discovered, check the token's permissions and the account's actual access to those repositories.

The script queries repositories associated with:

owner
collaborator
organization member

It cannot back up repositories to which the authenticated account has no access.


Network Errors

There are two separate network connections to GitHub.

API

api.github.com

Git over SSH

github.com:22

Test basic HTTPS connectivity:

curl -I https://api.github.com

Test GitHub SSH:

ssh -T git@github.com

If HTTPS works but SSH fails, the problem is likely related to:

  • firewall rules
  • outbound TCP/22 filtering
  • DNS
  • SSH configuration
  • network routing

SSH port 22 is blocked

Some networks block outbound SSH.

GitHub also provides SSH access through port 443.

However, the backup script currently uses the normal GitHub SSH endpoint. If your network blocks TCP/22, configure OpenSSH to use GitHub's SSH-over-443 endpoint.

For example:

Host github.com
    HostName ssh.github.com
    Port 443
    User git
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Test:

ssh -T git@github.com

The same configuration is then automatically used by Git because the script uses SSH URLs.


Permission Errors

Permission problems can occur locally even when GitHub authentication is working.

Backup directory is not writable

Check:

ls -ld /path/to/backup

Test writing:

touch /path/to/backup/.write-test
rm /path/to/backup/.write-test

If this fails, the user running the script does not have sufficient permissions.

Fix the ownership or permissions of the backup directory.

For example:

sudo chown -R backupuser:backupuser /path/to/backup

Use the appropriate user and group for your system.

Token file cannot be read

Check:

ls -l ~/.config/github/token

The file should normally look similar to:

-rw------- 1 user user ... token

If necessary:

chmod 600 ~/.config/github/token

Remember that scheduled tasks may run as a different user than interactive shell sessions.

A token located under:

/home/csiber/.config/github/token

will not automatically be available to a scheduled task running as another account.


Fetch / Mirror Update Errors

Existing repositories are updated with:

git remote update --prune

If this fails, test the mirror manually.

First check the repository:

git --git-dir=/path/to/repository.git rev-parse --is-bare-repository

Expected:

true

Check the configured remote:

git --git-dir=/path/to/repository.git remote -v

It should point to the expected GitHub SSH URL.

Example:

origin  git@github.com:owner/repository.git (fetch)
origin  git@github.com:owner/repository.git (push)

Test the remote:

git --git-dir=/path/to/repository.git ls-remote origin

If this fails, the problem is usually SSH authentication, repository permissions or network connectivity.

Manually update a mirror

You can run:

git --git-dir=/path/to/repository.git remote update --prune

This is the same operation used by the backup script for an existing mirror.

If it succeeds manually but fails through the scheduler, compare the execution environment.

In particular, check:

  • user account
  • $HOME
  • SSH key location
  • SSH configuration
  • token file location
  • mounted backup storage

Repository Does Not Exist

A repository may disappear from the GitHub API because it was:

  • deleted
  • renamed
  • transferred
  • made inaccessible to the authenticated account

The script does not automatically delete the local mirror.

Instead it reports it as an orphaned mirror.

Example:

ORPHANED MIRRORS

! old-project.git

The local copy is intentionally preserved.

Do not delete it automatically unless you have confirmed that it is no longer needed.


Disk Space Errors

Check available space:

df -h /path/to/backup

Check which repositories consume the most space:

du -sh /path/to/backup/*.git | sort -h

A GitHub repository's reported API size is only an estimate. The actual local mirror size can differ significantly because Git objects, history and other repository data may not correspond directly to the displayed GitHub size.

The first full mirror run can also temporarily generate significant disk activity.


Broken Mirror

If the script reports:

fetch failed

inspect the repository manually:

git --git-dir=/path/to/repository.git fsck

Check its remotes:

git --git-dir=/path/to/repository.git remote -v

Check its refs:

git --git-dir=/path/to/repository.git show-ref

Do not immediately delete a failed mirror.

Investigate the cause first.

If the local mirror is genuinely damaged and the GitHub repository is still accessible, it can be recreated after preserving the old copy.


Scheduled Task Works Differently

A very common source of confusion is:

Works manually
        ↓
Fails in Task Scheduler

Scheduled jobs often have a different environment.

Check the following:

whoami
echo "$HOME"
echo "$PATH"

The scheduled task should run as the same user that has:

  • the GitHub token
  • the SSH private key
  • access to the backup directory

Use absolute paths where practical.

The backup script itself already uses explicit paths for the backup destination and token file, which reduces environment-related problems.


Reading the Log

Every execution creates a log under:

_logs/

Example:

_logs/github-backup-2026-09-28_08-00-00.log

The log contains the same operational information displayed in the terminal, but without ANSI color escape sequences.

For a quick look at failures:

grep -A6 -B2 "FAILED" /path/to/backup/_logs/*.log

For the latest log:

ls -1t /path/to/backup/_logs/github-backup-*.log | head -1

Then:

less "$(ls -1t /path/to/backup/_logs/github-backup-*.log | head -1)"

Quick Diagnostic Checklist

When something fails, run these in order:

# 1. GitHub API
curl -fsSL \
  -H "Authorization: Bearer $(cat ~/.config/github/token)" \
  https://api.github.com/user

# 2. SSH
ssh -T git@github.com

# 3. GitHub repository access
git ls-remote git@github.com:OWNER/REPOSITORY.git

# 4. Local storage
df -h /path/to/backup

# 5. Local permissions
ls -ld /path/to/backup

# 6. Mirror state
git --git-dir=/path/to/repository.git remote -v

If all six work, the backup engine itself should normally be able to discover and mirror the repository.

Diagnostic flow

Backup failed
     │
     ├── API fails?
     │      └── Check token / GitHub API / network
     │
     ├── SSH fails?
     │      └── Check SSH key / account / network
     │
     ├── ls-remote fails?
     │      └── Check repository permissions / SSH
     │
     ├── Local write fails?
     │      └── Check NAS permissions / disk space
     │
     └── Only scheduled execution fails?
            └── Check user / HOME / SSH environment

When reporting a problem, include the relevant error from the backup log, but never include the GitHub Personal Access Token or private SSH key.