[PR #280] [MERGED] fix: unstick repos in 'mirroring' on transient errors (fixes #268) #2913

Closed
opened 2026-05-17 19:23:13 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/RayLabsHQ/gitea-mirror/pull/280
Author: @arunavo4
Created: 5/3/2026
Status: Merged
Merged: 5/4/2026
Merged by: @arunavo4

Base: mainHead: fix/issue-268-stuck-mirroring


📝 Commits (2)

  • 4351f4e fix: hoist migrateSucceeded above try so catch can update DB on failure (fixes #268)
  • bf0a2cd test: replace integration test with structural source check (#268)

📊 Changes

2 files changed (+140 additions, -6 deletions)

View changed files

src/lib/gitea-mirror-failure-recovery.test.ts (+132 -0)
📝 src/lib/gitea.ts (+8 -6)

📄 Description

Summary

  • Fixes #268 — repos stuck in mirroring state after transient network errors, with no failure entry in the activity log
  • Hoists let migrateSucceeded above the try block in mirrorGithubRepoToGitea and mirrorGitHubRepoToGiteaOrg so the catch block can actually read it
  • Adds regression tests that fail without the fix with the exact production error message

Root cause

let migrateSucceeded = false; was declared inside the try block. let is block-scoped, so the catch block at the bottom of the same function couldn't see it. When any operation inside try threw (timeout to Gitea, 4xx/5xx, etc.), the catch block crashed with ReferenceError: migrateSucceeded is not defined before it could:

  • update the repo to status: "failed"
  • clear mirroredLocation
  • write a "failed" activity-log entry
  • re-throw the original error

So the repo was permanently stuck in mirroring, no failure log appeared, and the user-visible error on retry was the misleading Failed to mirror repository: migrateSucceeded is not defined instead of the real cause.

This was visible in elpastorios's logs on the issue:

Error while mirroring repository <REPO>: Network error: The operation timed out.
Retrying repository <REPO> (attempt 1): Failed to mirror repository: migrateSucceeded is not defined

The first line is the catch's console.error (runs before the bad reference); the second is the wrapper from mirrorGitHubOrgRepoToGiteaOrg's outer catch at gitea.ts:1857.

TypeScript was already flagging Cannot find name 'migrateSucceeded' at the catch lines — but esbuild strips types during build, so the bug shipped.

Introduced in #236.

What this fix does NOT cover

The trigger — Gitea's /repos/migrate timing out client-side while continuing in the background — still leaves orphan repos that retries see and rename to repo-1, repo-2 (the duplicates in elpastorios's screenshot). That's a separate fix; options include probing Gitea after a timeout, raising the migrate timeout, or making generateUniqueRepoName aware of orphans owned by this user. Worth following up on but out of scope here — this PR stops the bleeding so transient errors no longer leave repos permanently stuck.

Test plan

  • New regression tests in src/lib/gitea-mirror-failure-recovery.test.ts cover both mirrorGithubRepoToGitea and mirrorGitHubRepoToGiteaOrg. They force httpPost to reject and assert:
    • the thrown error preserves the original message (not migrateSucceeded is not defined)
    • the DB is updated with status: "failed" and mirroredLocation: ""
    • createMirrorJob is called with status: "failed"
  • Verified tests fail on the buggy code with Received: "migrateSucceeded is not defined" — exact production error
  • bun test — 233 pass, 0 fail across 39 files
  • Manual verification on a Gitea instance: trigger a mirror against an unreachable Gitea URL, confirm the repo lands in failed and a failure entry appears in Activity Logs

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/RayLabsHQ/gitea-mirror/pull/280 **Author:** [@arunavo4](https://github.com/arunavo4) **Created:** 5/3/2026 **Status:** ✅ Merged **Merged:** 5/4/2026 **Merged by:** [@arunavo4](https://github.com/arunavo4) **Base:** `main` ← **Head:** `fix/issue-268-stuck-mirroring` --- ### 📝 Commits (2) - [`4351f4e`](https://github.com/RayLabsHQ/gitea-mirror/commit/4351f4e233ce9b0a28e3bca4859b2bf28044ab4b) fix: hoist migrateSucceeded above try so catch can update DB on failure (fixes #268) - [`bf0a2cd`](https://github.com/RayLabsHQ/gitea-mirror/commit/bf0a2cd54aa9cf6f99f3922c237b7cf365c40a6d) test: replace integration test with structural source check (#268) ### 📊 Changes **2 files changed** (+140 additions, -6 deletions) <details> <summary>View changed files</summary> ➕ `src/lib/gitea-mirror-failure-recovery.test.ts` (+132 -0) 📝 `src/lib/gitea.ts` (+8 -6) </details> ### 📄 Description ## Summary - Fixes [#268](https://github.com/RayLabsHQ/gitea-mirror/issues/268) — repos stuck in `mirroring` state after transient network errors, with no failure entry in the activity log - Hoists `let migrateSucceeded` above the `try` block in `mirrorGithubRepoToGitea` and `mirrorGitHubRepoToGiteaOrg` so the `catch` block can actually read it - Adds regression tests that fail without the fix with the exact production error message ## Root cause `let migrateSucceeded = false;` was declared *inside* the `try` block. `let` is block-scoped, so the `catch` block at the bottom of the same function couldn't see it. When any operation inside `try` threw (timeout to Gitea, 4xx/5xx, etc.), the catch block crashed with `ReferenceError: migrateSucceeded is not defined` *before* it could: - update the repo to `status: "failed"` - clear `mirroredLocation` - write a `"failed"` activity-log entry - re-throw the original error So the repo was permanently stuck in `mirroring`, no failure log appeared, and the user-visible error on retry was the misleading `Failed to mirror repository: migrateSucceeded is not defined` instead of the real cause. This was visible in elpastorios's logs on the issue: ``` Error while mirroring repository <REPO>: Network error: The operation timed out. Retrying repository <REPO> (attempt 1): Failed to mirror repository: migrateSucceeded is not defined ``` The first line is the catch's `console.error` (runs before the bad reference); the second is the wrapper from `mirrorGitHubOrgRepoToGiteaOrg`'s outer catch at `gitea.ts:1857`. TypeScript was already flagging `Cannot find name 'migrateSucceeded'` at the catch lines — but esbuild strips types during build, so the bug shipped. Introduced in #236. ## What this fix does NOT cover The *trigger* — Gitea's `/repos/migrate` timing out client-side while continuing in the background — still leaves orphan repos that retries see and rename to `repo-1`, `repo-2` (the duplicates in elpastorios's screenshot). That's a separate fix; options include probing Gitea after a timeout, raising the migrate timeout, or making `generateUniqueRepoName` aware of orphans owned by this user. Worth following up on but out of scope here — this PR stops the bleeding so transient errors no longer leave repos permanently stuck. ## Test plan - [x] New regression tests in `src/lib/gitea-mirror-failure-recovery.test.ts` cover both `mirrorGithubRepoToGitea` and `mirrorGitHubRepoToGiteaOrg`. They force `httpPost` to reject and assert: - the thrown error preserves the original message (not `migrateSucceeded is not defined`) - the DB is updated with `status: "failed"` and `mirroredLocation: ""` - `createMirrorJob` is called with `status: "failed"` - [x] Verified tests fail on the buggy code with `Received: "migrateSucceeded is not defined"` — exact production error - [x] `bun test` — 233 pass, 0 fail across 39 files - [ ] Manual verification on a Gitea instance: trigger a mirror against an unreachable Gitea URL, confirm the repo lands in `failed` and a failure entry appears in Activity Logs --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-05-17 19:23:13 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea-mirror#2913