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
- Call `receive()` exactly once per fetch connection; restructure code so the result is stored, not re-obtained.
- For a new fetch, create a new connection via `remote.connect(Direction::Fetch)` and restart the handshake.
- 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
- Treat receive() as a consuming one-shot: take ownership and move the result
- Never call receive() inside loops or retry helpers on the same value
- Reconnect (remote.connect) for every additional fetch
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
- Tried to use as tree, but was
- Tried to use as commit, but was
- Tried to use as tag, but was
- invalid mode change: can't flip executable bit of
- visit_non_tree() called us
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
.resolvedView on GitHub (pinned to e73179060b)