{"record":{"id":"6d4321843901dc01","repo":"gitbutlerapp/gitbutler","slug":"existing-gitmeta-key-local-key-is-not-a-set","errorCode":null,"errorMessage":"existing GitMeta key '{local_key}' is not a set","messagePattern":"existing GitMeta key '(.+?)' is not a set","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-agentlog/src/gitmeta/share.rs","lineNumber":79,"sourceCode":"    Ok(())\n}\n\nfn index_set_member_shares(\n    handle: &git_meta_lib::SessionTargetHandle<'_>,\n    session_keys: &[String],\n) -> Result<Vec<SetMemberShare>> {\n    let selected_sessions = session_keys\n        .iter()\n        .map(String::as_str)\n        .collect::<BTreeSet<_>>();\n    let index_prefix = local_storage_key(INDEX_NAMESPACE);\n    let mut shares = BTreeMap::<String, SetMemberShare>::new();\n    for (local_key, value) in handle\n        .get_all_values(Some(&index_prefix))\n        .with_context(|| format!(\"failed to read GitMeta keys under '{index_prefix}'\"))?\n    {\n        let MetaValue::Set(members) = value else {\n            bail!(\"existing GitMeta key '{local_key}' is not a set\");\n        };\n        let Some(published_key) = strip_local_storage_prefix(&local_key) else {\n            continue;\n        };\n        let published_key = published_key.to_owned();\n        let selected_members = members\n            .into_iter()\n            .filter(|member| match serde_json::from_str::<IndexHit>(member) {\n                Ok(hit) => selected_sessions.contains(hit.session_key.as_str()),\n                Err(_) => false,\n            })\n            .collect::<Vec<_>>();\n        if selected_members.is_empty() {\n            continue;\n        }\n        shares.insert(\n            local_key.clone(),\n            SetMemberShare {","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-agentlog/src/gitmeta/share.rs#L61-L97","documentation":"Unpublished (local-only) sessions are tracked under a local index namespace as `MetaValue::Set` keys, each holding JSON `IndexHit` members. `share.rs` iterates all keys under that prefix via `get_all_values` and bails on the first key that is not a Set. Because it scans every key under the prefix, one malformed key disables the whole share/publish flow.","triggerScenarios":"`but agentlog publish <target>` (and dry-run) scanning local index keys when any `local_storage_key(INDEX_NAMESPACE)`-prefixed key holds a String or List instead of a Set of IndexHit JSON entries.","commonSituations":"Leftover keys from an older but-agentlog format under the same prefix; manual writes into the local index namespace; a partially-completed migration between local key layouts.","solutions":["Run `but agentlog sync` then retry publish","Locate the malformed key (list all keys under the local index prefix with their MetaValue variants) and delete or rewrite it","Align `but` versions so only one local-index format is written","If the local index is fully stale, remove the namespace's keys and let the next capture rebuild it"],"exampleFix":"// before\nlet MetaValue::Set(members) = value else { bail!(\"...\") };\n\n// after: skip malformed local index keys instead of aborting the scan\nlet members = match value {\n    MetaValue::Set(members) => members,\n    _ => continue,\n};","handlingStrategy":"validation","validationCode":"// Pre-scan local index keys and report any non-Set members before publish\nfor (key, value) in handle.get_all_values(Some(&index_prefix))? {\n    if !matches!(value, MetaValue::Set(_)) {\n        eprintln!(\"malformed local index key: {key}\");\n    }\n}","typeGuard":"fn local_index_is_set(v: &MetaValue) -> bool {\n    matches!(v, MetaValue::Set(_))\n}","tryCatchPattern":"let members = match value {\n    MetaValue::Set(members) => members,\n    _ => continue, // skip malformed local index keys\n};","preventionTips":["Do not write keys under the agentlog local index namespace from outside but-agentlog","After version changes, let one capture cycle rebuild the local index","Run publish with --dry-run first to surface malformed keys cheaply"],"tags":["gitmeta","type-mismatch","local-index","publish","share","rust"],"backgroundTag":"stored-data-type-mismatch","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}