GitoxideLabs/gitoxide · error

present as checkout operation isn't complete

Error message

present as checkout operation isn't complete

What it means

PrepareCheckout::repo() unwraps the internal Option<Repository>, asserting the repository is still present. Once checkout completed and the Repository was moved out (via main_worktree success or persist()), the invariant documented on the method (# Panics: if the checkout is completed) no longer holds and it panics.

Solutions

  1. Only call repo() while checkout is still in progress (before main_worktree() returns Ok).
  2. Use persist() exactly once to obtain the Repository when done.
  3. Restructure to pass the Repository returned from main_worktree() instead of querying repo() later.

Example fix

// before
let repo = prepare.main_worktree(...)?;
prepare.repo(); // panics: checkout completed
// after
let repo = prepare.main_worktree(...)?;
// use `repo` directly
Defensive patterns

Strategy: type-guard

Validate before calling

// Only query repo() before starting checkout:
if !checkout_started { let repo = prepare.repo(); }

Prevention

When it happens

Trigger: Calling .repo() on a PrepareCheckout after main_worktree() returned Ok and the repository was passed to the caller, or after persist() was invoked.

Common situations: Storing PrepareCheckout and reading repo() at multiple points; calling repo() in a Drop path after persist(); logging/inspection code run after completion.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/7901631295ef3ff6. Report an issue: GitHub.

Appendix: source

Thrown at gix/src/clone/checkout.rs:159

            bytes.show_throughput(start);

            index.write(Default::default())?;
            Ok((self.repo.take().expect("still present").clone(), outcome))
        }
    }
}

/// Access
impl PrepareCheckout {
    /// Get access to the repository while the checkout isn't yet completed.
    ///
    /// # Panics
    ///
    /// If the checkout is completed and the [`Repository`] was already passed on to the caller.
    pub fn repo(&self) -> &Repository {
        self.repo
            .as_ref()
            .expect("present as checkout operation isn't complete")
    }
}

/// Consumption
impl PrepareCheckout {
    /// Persist the contained repository as is even if an error may have occurred when checking out the main working tree.
    pub fn persist(mut self) -> Repository {
        self.repo.take().expect("present and consumed once")
    }
}

impl Drop for PrepareCheckout {
    fn drop(&mut self) {
        if let Some(repo) = self.repo.take() {
            super::cleanup_clone_destination_on_drop(&repo, self.remove_worktree_on_drop);
        }
    }
}

View on GitHub (pinned to e73179060b)