Skip to content

fix(skills-init): clean stale dest before cloning - #2350

Open
mario-valente wants to merge 1 commit into
kagent-dev:mainfrom
mario-valente:fix/skillsinit-clean-stale-dest
Open

fix(skills-init): clean stale dest before cloning#2350
mario-valente wants to merge 1 commit into
kagent-dev:mainfrom
mario-valente:fix/skillsinit-clean-stale-dest

Conversation

@mario-valente

@mario-valente mario-valente commented Jul 28, 2026

Copy link
Copy Markdown

Summary

CloneGit never removes a pre-existing ref.Dest before starting a clone, so a leftover from any prior failed attempt permanently poisons every retry with destination path already exists and is not an empty directory — the pre-flight check in git's own clone fails before any network I/O.

Note on how this was hit: in our case the original trigger of that first failed attempt was a separate bug in this same file — Full: true's git checkout -- <ref.Ref> treats a 40-hex SHA as a pathspec (because of the -- separator) and always exits 1, so the clone (step 1) succeeds and leaves dest fully populated, but the checkout (step 2) fails every time and applySubPath never runs. I'm not fixing that pathspec bug here (worked around it operationally by switching to a branch/tag ref, avoiding the Full: true path entirely) but wanted to flag it separately since it's the more common way to end up in the stuck state this PR fixes. Filing this PR for the general idempotency gap regardless: any interrupted attempt (OOM, node preemption, unrelated pod restart) leaves the same poisoned dest, not just the pathspec case.

Fix

os.RemoveAll(ref.Dest) at the top of CloneGit, before any clone attempt, so every invocation genuinely starts from scratch — matching what Run's own doc comment already claims happens ("the container restarts and re-runs from scratch").

Test plan

  • Added Test_CloneGit_cleansStaleDest: seeds dest with leftover content from a simulated interrupted attempt, then asserts CloneGit against a local git fixture repo succeeds and the stale content is gone.
  • go test ./core/internal/skillsinit/... — all passing (including pre-existing tests, no regressions).

CloneGit never removed a pre-existing ref.Dest before starting. A prior
attempt killed between the clone/checkout and applySubPath's final
os.Rename leaves the full clone sitting in dest — non-empty, but not yet
reduced to the subPath. Every subsequent retry then fails git's own
pre-flight "already exists and is not an empty directory" check before
touching the network, permanently, even though the container is documented
to retry from scratch on failure.

Reproduced against a real Agent on AKS: skills-init crash-looped forever
after the first (interrupted) attempt left a full-repo clone behind.

Fix: os.RemoveAll(ref.Dest) at the top of CloneGit, before any clone
attempt, so every invocation genuinely starts from scratch as intended.
@mario-valente
mario-valente requested a review from a team as a code owner July 28, 2026 13:34
Copilot AI review requested due to automatic review settings July 28, 2026 13:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Ensures CloneGit retries truly start from a clean slate by deleting any pre-existing destination directory, preventing permanent failures after interrupted clones (especially when subPath rewriting is involved).

Changes:

  • Remove ref.Dest at the start of CloneGit to avoid git clone failing on non-empty destinations.
  • Add a regression test that simulates a stale destination and asserts CloneGit succeeds and removes leftover files.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
go/core/internal/skillsinit/git.go Deletes ref.Dest before cloning to guarantee retry-from-scratch semantics.
go/core/internal/skillsinit/clonegit_stale_dest_test.go Adds a regression test proving stale destination cleanup works.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +29 to +31
if err := os.RemoveAll(ref.Dest); err != nil {
return fmt.Errorf("clean stale dest %q: %w", ref.Dest, err)
}
}

origin := t.TempDir()
runIn(t, origin, "init", "--initial-branch=main")
@github-actions github-actions Bot added the bug Something isn't working label Jul 28, 2026
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants