GitoxideLabs/gitoxide · error

BUG: expected peeled reference target but found symbolic one

Error message

BUG: expected peeled reference target but found symbolic one

What it means

`gix_ref::Target::into_id()` consumes the target and returns the owned object id, panicking with 'BUG: expected peeled reference target but found symbolic one' if the target is `Target::Symbolic`. Same contract as `.id()` but for owned consumption; symbolic targets simply have no id to give.

Solutions

  1. Use `try_into_id()` which returns `Err(Self)` for symbolic targets and handle it
  2. Resolve symbolic refs to their final object id before calling `into_id()`
  3. Match on the target and convert each variant appropriately
  4. Add a debug_assert or type-level separation ensuring only peeled targets reach this call

Example fix

// before
let oid = target.into_id(); // panics if symbolic
// after
let oid = target.try_into_id().map_err(|_| anyhow::anyhow!("target was symbolic"))?;
Defensive patterns

Strategy: type-guard

Validate before calling

let oid = match target {
    gix_ref::Target::Object(oid) => oid,
    t @ gix_ref::Target::Symbolic(_) => return Err(anyhow::anyhow!("symbolic: {:?}", t)),
};

Type guard

fn try_owned_id(target: gix_ref::Target) -> Result<gix_hash::ObjectId, gix_ref::Target> {
    target.try_into_id()
}

Prevention

When it happens

Trigger: Calling `target.into_id()` on a `Target::Symbolic(name)`, e.g. converting HEAD's raw target into an `ObjectId` without first resolving the ref chain.

Common situations: Refactorings from `.id().to_owned()` to `into_id()` that dropped an existing peel step; code paths that assumed pre-peeled input from callers; processing ref transaction logs containing symbolic entries.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at gix-ref/src/target.rs:84

    /// Interpret this target as object id which maybe `None` if it is symbolic.
    pub fn try_id(&self) -> Option<&oid> {
        match self {
            Target::Symbolic(_) => None,
            Target::Object(oid) => Some(oid),
        }
    }
    /// Interpret this target as object id or panic if it is symbolic.
    pub fn id(&self) -> &oid {
        match self {
            Target::Symbolic(_) => panic!("BUG: tries to obtain object id from symbolic target"),
            Target::Object(oid) => oid,
        }
    }
    /// Return the contained object id or panic
    pub fn into_id(self) -> ObjectId {
        match self {
            Target::Symbolic(_) => panic!("BUG: expected peeled reference target but found symbolic one"),
            Target::Object(oid) => oid,
        }
    }

    /// Return the contained object id if the target is peeled or itself if it is not.
    pub fn try_into_id(self) -> Result<ObjectId, Self> {
        match self {
            Target::Symbolic(_) => Err(self),
            Target::Object(oid) => Ok(oid),
        }
    }
    /// Interpret this target as name of the reference it points to which maybe `None` if it an object id.
    pub fn try_name(&self) -> Option<&FullNameRef> {
        match self {
            Target::Symbolic(name) => Some(name.as_ref()),
            Target::Object(_) => None,
        }
    }

View on GitHub (pinned to e73179060b)