GitoxideLabs/gitoxide · error

present and consumed once

Error message

present and consumed once

What it means

PrepareCheckout::persist() calls self.repo.take().expect("present and consumed once"). It consumes the value via `mut self`, so the Option must still be Some when persist runs. It panics if the repository was already taken - i.e. persist() was called twice, or the repo was already handed over by a successful checkout flow before persist().

Solutions

  1. Call persist() exactly once; persist consumes self so the value cannot be used afterwards.
  2. If checkout succeeded, use the Repository returned by main_worktree() instead of calling persist().
  3. Rely on Drop to persist automatically if you cannot decide in code - do not double-persist.

Example fix

// before
let repo = prepare.persist();
let again = prepare.persist(); // compile error / cannot reuse; pattern of double-consume panics in Drop paths
// after
let repo = prepare.persist(); // exactly once, value consumed
Defensive patterns

Strategy: validation

Validate before calling

// persist() consumes self, so the compiler enforces single use; ensure one code path owns it:
let repo = prepare.persist();

Prevention

When it happens

Trigger: Calling persist() twice on the same PrepareCheckout; calling persist() after main_worktree() succeeded and the caller already owns the Repository; calling persist() after the value was previously consumed internally.

Common situations: Error-handling paths that persist in multiple branches; storing the value and calling persist in a helper plus a fallback; confusing persist() with a getter.

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/83adf8c014ee7b89. Report an issue: GitHub.

Appendix: source

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

/// 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);
        }
    }
}

impl From<PrepareCheckout> for Repository {
    fn from(prep: PrepareCheckout) -> Self {
        prep.persist()
    }
}

View on GitHub (pinned to e73179060b)