Troubleshooting¶
Common issues and their solutions.
Container Startup¶
MASTER_KEY is required¶
Cause: The MASTER_KEY environment variable is not set. GitEcho refuses to start and surfaces a 503 page:
Fix: Generate a key and add it to your configuration:
Add the output as MASTER_KEY in your docker-compose.yml or -e MASTER_KEY=... in your docker run command.
Mount point permission errors (Synology / NAS)¶
Cause: Docker bind mounts inherit host ownership. The container's gitecho user can't write to the mounted directories.
Fix: Set PUID and PGID to match the host directory owner:
# On the host, check ownership:
ls -ldn /volume1/docker/gitecho/config
# First number = UID, second = GID
# In docker-compose.yml:
environment:
PUID: "1026"
PGID: "100"
Then recreate the container:
If Synology ACLs are involved (a + in the permission bits), also grant full rights via DSM → Shared Folder → Permissions.
Authentication¶
Login redirects back with error=invalid¶
Cause: Wrong username or password. The default bootstrap is admin / admin.
Fix: To reset credentials, stop the container and delete /config/secrets.json, then restart. GitEcho will re-bootstrap the default admin account.
"Password change required" blocks everything¶
Cause: This is expected behavior on first login. GitEcho forces a password change before allowing any other navigation.
Fix: Complete the password change at /settings/account.
Login fails with Unexpected token 'C', "Cross-site"... is not valid JSON¶
Cause: The browser is accessing GitEcho via a hostname or port that doesn't match the PUBLIC_URL environment variable (or it's not set). The middleware rejects the POST request as a cross-site forgery, returning plain-text "Cross-site requests are not allowed" which the browser tries to parse as JSON, triggering the error.
Fix: Set PUBLIC_URL to match the URL in your browser's address bar:
# Example: accessing via http://192.168.1.100:3000
docker compose down
export PUBLIC_URL="http://192.168.1.100:3000"
docker compose up -d
# Or in docker-compose.yml:
# environment:
# PUBLIC_URL: "http://192.168.1.100:3000"
If you have multiple access paths (e.g. http://localhost:3000 and http://192.168.1.100:3000), list them comma-separated:
To disable the CSRF origin check entirely (not recommended for production):
Why are only public GitHub repositories discovered?¶
Cause: The configured GitHub PAT does not have the required scope/permissions for private repository discovery.
GitEcho's GitHub discovery path relies on gh repo list, and the token must include:
- Classic PAT:
repoandread:org(especially required for private org repositories) - Fine-grained PAT: Repository permissions Metadata: Read and Contents: Read, plus explicit access to the target repository/repositories or organization
If these permissions are missing, discovery may return only public repositories or an incomplete subset.
Fix: Create/update the PAT with the required permissions, then run Settings → Providers → GitHub → Discover now.
Backup Issues¶
Worker logs Another process is already running a backup¶
Cause: A previous backup run crashed and left /data/.backup.lock. The lock self-heals once the recorded PID is no longer alive. While the lock is held, the dashboard's Quick Actions card reflects this:
Fix: If the lock persists, delete the file manually:
One repo fails while others succeed¶
Common errors: curl 56 Recv failure: Connection reset by peer, fatal: early EOF, HTTP/2 stream CANCEL, fetch-pack: unexpected disconnect
Diagnosis:
-
Open
/settings/repos/<id>and enable Verbose git trace (debug) -
Trigger a backup (scheduled or manual)
-
Download the captured log from the Debug traces card
-
The log contains full
GIT_TRACE,GIT_CURL_VERBOSE,GIT_TRACE_PACKET, and timing information - Turn the toggle off when done — traces can be tens of MiB
Common root causes:
- Docker bridge MTU (try setting
com.docker.network.driver.mtu: 1400) - ISP/DPI resetting long-running connections
- Container OOM during
index-packon large repos - Azure DevOps
dev.azure.comvs*.visualstudio.comrouting issues
Unavailable upstream repositories¶
When a repo can't be reached (deleted, renamed, made private, PAT unauthorized, 404/403):
- GitEcho continues the run for all remaining repositories
- The affected repo is marked with
unavailablestatus - Existing local backups are kept untouched — nothing is deleted
- Once the upstream becomes reachable again, the next successful backup transitions it back to
success
The dashboard surfaces a banner whenever any repo is in this state:
PAT expiry warnings¶
GitEcho records the expiration date you enter alongside each PAT and warns on the dashboard when one is within seven days of expiring.
Archiving vs. deleting a repository¶
From Settings → Repositories → \<id>, the Danger Zone offers two terminal actions:
Moves any existing backup to /backups/_archived/<provider>/<owner>/<repo>/<timestamp>/
and stops further backup attempts. The repo is hidden from auto-discovery and the
main repos list, but stays available under Settings → Repositories → Archived
so you can review or unarchive it later. Confirmation requires re-typing the repo slug.
Cleaning up repos.txt¶
If an entry in repos.txt duplicates a repository the active PAT can already discover,
GitEcho flags it as redundant. Open Settings → Repositories → Cleanup to review and
remove redundant entries in one shot.
CLI Tools¶
gh: command not found¶
Cause: GitHub CLI is not installed. Inside the container, it's pre-installed. This error appears in local development.
Fix: Install GitHub CLI: brew install gh or visit cli.github.com
glab: command not found¶
Cause: GitLab CLI is installed inside the Docker image but may not be present locally.
Fix: For local development, glab is optional — the Astro dev server uses the GitLab REST API directly. Install via brew install glab if needed.
better-sqlite3 build error¶
Cause: Node.js version mismatch. The prebuilt binary targets Node 22.
Fix: Use Node 22 (nvm use 22). If that doesn't help, install python3 and a C++ toolchain for native compilation.
Cron Schedule¶
Schedule changed but worker still uses the old one¶
Cause: The cron schedule is bound at worker startup.
Fix: Restart the worker process:
# Docker
docker compose restart gitecho
# Local development
# Restart the npm run worker:dev terminal
Network / Proxy¶
403 Forbidden on save/delete actions behind a reverse proxy¶
Cause: The browser's Origin header doesn't match the container's internal host, and PUBLIC_URL is not set.
Fix: Set PUBLIC_URL to your external URL(s):









