GitoxideLabs/gitoxide · error

receive() can only be called once

Error message

receive() can only be called once

What it means

`FetchConnection::receive()` consumes the connection (`self.con.take()`) so it can only be called once; a second call finds `None` and the `expect` panics. It is an intentional misuse guard: the receive phase hands ownership of the connection and handshake to the streaming result. Any follow-up operation requires setting up a new connection/fetch.

Solutions

  1. Call `receive()` exactly once per fetch connection; restructure code so the result is stored, not re-obtained.
  2. For a new fetch, create a new connection via `remote.connect(Direction::Fetch)` and restart the handshake.
  3. If you need the value repeatedly, clone/extract needed data (refs, pack) from the single receive result before dropping it.

Example fix

// before
let first = receive_pack.receive()?;
let again = receive_pack.receive()?; // panic
// after
let first = receive_pack.receive()?; // consume once
// for more data, reconnect:
let mut con = remote.connect(gix::remote::Direction::Fetch)?;
Defensive patterns

Strategy: validation

Validate before calling

// track consumption yourself
let mut received = false;
if received { return Err(anyhow::anyhow!("receive() already called")); }
received = true;
let result = receive_pack.receive()?;

Prevention

When it happens

Trigger: Calling `.receive()` twice on the same `receive_pack` value, e.g. storing the result and calling `receive()` again after an earlier call succeeded or after partial consumption.

Common situations: Retry logic that re-invokes `receive()` on the same object instead of redialing; wrapping code that calls receive in a helper called more than once.

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

Appendix: source

Thrown at gix/src/remote/connection/fetch/receive_pack.rs:108

        repo: &crate::Repository,
        progress: P,
        should_interrupt: &AtomicBool,
    ) -> Result<Outcome, Error>
    where
        P: gix_features::progress::NestedProgress,
        P::SubProgress: 'static,
    {
        let ref_map = &self.ref_map;
        if ref_map.is_missing_required_mapping() {
            let mut specs = ref_map.refspecs.clone();
            specs.extend(ref_map.extra_refspecs.clone());
            return Err(Error::NoMapping {
                refspecs: specs,
                num_remote_refs: ref_map.remote_refs.len(),
            });
        }

        let mut con = self.con.take().expect("receive() can only be called once");
        let mut handshake = con.handshake.take().expect("receive() can only be called once");

        let expected_object_hash = repo.object_hash();
        if ref_map.object_hash != expected_object_hash {
            return Err(Error::IncompatibleObjectHash {
                local: expected_object_hash,
                remote: ref_map.object_hash,
            });
        }

        let fetch_options = gix_protocol::fetch::Options {
            shallow_file: repo.shallow_file(),
            shallow: &self.shallow,
            tags: con.remote.fetch_tags,
            reject_shallow_remote: Clone::REJECT_SHALLOW
                .enrich_error(
                    repo.config
                        .resolved

View on GitHub (pinned to e73179060b)