{"record":{"id":"fde06ee8cf3dc69a","repo":"gitbutlerapp/gitbutler","slug":"but-meta-stack-derived-name-stack-is-uninitiali","errorCode":null,"errorMessage":"but_meta::Stack::derived_name: Stack is uninitialized","messagePattern":"but_meta::Stack::derived_name: Stack is uninitialized","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/but-meta/src/virtual_branches_legacy_types.rs","lineNumber":97,"sourceCode":"        )]\n        #[serde(default)]\n        pub updated_timestamp_ms: u128,\n        #[deprecated(note = \"Legacy field, do not use. Kept for backwards compatibility.\")]\n        #[serde(default)]\n        pub name: String,\n        #[deprecated(note = \"Legacy field, do not use. Kept for backwards compatibility.\")]\n        #[serde(with = \"but_serde::object_id\")]\n        #[serde(default = \"default_null_object_id\")]\n        pub head: gix::ObjectId,\n    }\n\n    impl Stack {\n        /// This is the name of the top-most branch, provided by the API for convenience.\n        pub fn derived_name(&self) -> anyhow::Result<String> {\n            self.heads\n                .last()\n                .map(|head| head.name.clone())\n                .ok_or_else(|| anyhow!(\"but_meta::Stack::derived_name: Stack is uninitialized\"))\n        }\n    }\n\n    fn default_null_object_id() -> gix::ObjectId {\n        gix::hash::Kind::Sha1.null()\n    }\n\n    fn default_true() -> bool {\n        true\n    }\n    fn default_false() -> bool {\n        false\n    }\n\n    fn serialize_u128<S>(x: &u128, s: S) -> anyhow::Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-meta/src/virtual_branches_legacy_types.rs#L79-L115","documentation":"Returned by Stack::derived_name in crates/but-meta/src/virtual_branches_legacy_types.rs when the legacy Stack has an empty heads vector — derived_name takes the name of the top-most head (heads.last()), and with no heads there is no name to derive, so the stack is treated as uninitialized.","triggerScenarios":"Deserializing a legacy stack entry that lists no heads (serde default empty vec) and then calling derived_name() on it; stacks created but never assigned branches in old data; migration code calling derived_name over all stacks without filtering.","commonSituations":"Processing imported or hand-written legacy metadata containing zero-head stacks; a partially written stack entry from an old crash; iterating stacks from an older format where heads were stored separately and the link was lost.","solutions":["Guard callers: skip stacks whose heads are empty instead of calling derived_name on them.","Filter during migration so only initialized stacks (heads non-empty) are converted.","If every stack is empty, the source metadata is malformed — restore from backup or reinitialize."],"exampleFix":"// before\nlet name = stack.derived_name()?;\n\n// after\nlet name = stack\n    .heads\n    .last()\n    .map(|head| head.name.clone())\n    .unwrap_or_else(|| \"(uninitialized)\".to_string());","handlingStrategy":"type-guard","validationCode":"// Only derive names for initialized stacks\nfor stack in stacks {\n    if stack.heads.is_empty() {\n        continue; // skip uninitialized legacy stack\n    }\n    let name = stack.derived_name()?;\n}","typeGuard":"fn stack_is_initialized(stack: &Stack) -> bool {\n    !stack.heads.is_empty()\n}","tryCatchPattern":"let name = match stack.derived_name() {\n    Ok(n) => n,\n    Err(e) if e.to_string().contains(\"uninitialized\") => {\n        tracing::warn!(\"skipping uninitialized stack {:?}\", stack); continue;\n    },\n    Err(e) => return Err(e),\n};","preventionTips":["Filter stacks by !heads.is_empty() before any derived_name() call in migration code.","Treat zero-head stacks as data to be skipped or reported, not hard failures.","Unit-test parsers against empty-head fixtures so this path is covered."],"tags":["metadata","legacy-migration","virtual-branches","state-validation"],"backgroundTag":"uninitialized-state","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}