{"record":{"id":"77778bee495ba98e","repo":"GitoxideLabs/gitoxide","slug":"bug-tries-to-obtain-object-id-from-symbolic-targe","errorCode":null,"errorMessage":"BUG: tries to obtain object id from symbolic target","messagePattern":"BUG: tries to obtain object id from symbolic target","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-ref/src/target.rs","lineNumber":25,"sourceCode":"impl TargetRef<'_> {\n    /// Returns the kind of the target the ref is pointing to.\n    pub fn kind(&self) -> Kind {\n        match self {\n            TargetRef::Symbolic(_) => Kind::Symbolic,\n            TargetRef::Object(_) => Kind::Object,\n        }\n    }\n    /// Interpret this target as object id which maybe `None` if it is symbolic.\n    pub fn try_id(&self) -> Option<&oid> {\n        match self {\n            TargetRef::Symbolic(_) => None,\n            TargetRef::Object(oid) => Some(oid),\n        }\n    }\n    /// Interpret this target as object id or **panic** if it is symbolic.\n    pub fn id(&self) -> &oid {\n        match self {\n            TargetRef::Symbolic(_) => panic!(\"BUG: tries to obtain object id from symbolic target\"),\n            TargetRef::Object(oid) => oid,\n        }\n    }\n    /// Interpret this target as name of the reference it points to which maybe `None` if it an object id.\n    pub fn try_name(&self) -> Option<&FullNameRef> {\n        match self {\n            TargetRef::Symbolic(name) => Some(name),\n            TargetRef::Object(_) => None,\n        }\n    }\n    /// Convert this instance into an owned version, without consuming it.\n    pub fn into_owned(self) -> Target {\n        self.into()\n    }\n}\n\nimpl Target {\n    /// Returns the kind of the target the ref is pointing to.","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-ref/src/target.rs#L7-L43","documentation":"`gix_ref::TargetRef::id()` interprets a reference target as an object id and panics with a `BUG:` message if the target is symbolic (points at another ref name). Symbolic targets carry a `FullName`, not an oid, so requesting `.id()` on one is a caller-side logic error, treated as an internal invariant violation.","triggerScenarios":"Calling `target.id()` on a `TargetRef::Symbolic(name)` — e.g. on the target of `HEAD` in a freshly cloned repo, which is typically `Symbolic(refs/heads/main)`.","commonSituations":"Inspecting HEAD's target without unpacking the symbolic chain; reading packed-refs or loose ref entries and assuming they are peeled; iterating refs and calling `.id()` uniformly on all targets.","solutions":["Match on the target first: only call `.id()` for `TargetRef::Object`","Use `target.try_id()` (or `try_name()` for symbolic) to handle both variants safely","Resolve symbolic refs to their peeled target first (e.g. via ref resolution APIs)","Follow the ref chain until you reach an object target, then take its id"],"exampleFix":"// before\nlet oid = head_target.id(); // panics if HEAD is symbolic\n// after\nlet oid = head_target.try_id().ok_or_else(|| anyhow::anyhow!(\"HEAD is symbolic, resolve it first\"))?;","handlingStrategy":"type-guard","validationCode":"let oid = match target {\n    gix_ref::TargetRef::Object(oid) => Some(oid),\n    gix_ref::TargetRef::Symbolic(_) => None,\n};","typeGuard":"fn peeled(target: &gix_ref::TargetRef<'_>) -> Option<&gix_hash::oid> {\n    target.try_id()\n}","tryCatchPattern":null,"preventionTips":["Never assume a ref target is peeled; HEAD usually is not","Use try_id()/try_name() at every target access","Resolve symbolic refs before oid extraction"],"tags":["rust","panic","refs","symbolic-ref"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}