gitbutlerapp/gitbutler · error
existing GitMeta key '{local_key}' is not a set
Error message
existing GitMeta key '{local_key}' is not a set What it means
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.
Source
Thrown at crates/but-agentlog/src/gitmeta/share.rs:79
Ok(())
}
fn index_set_member_shares(
handle: &git_meta_lib::SessionTargetHandle<'_>,
session_keys: &[String],
) -> Result<Vec<SetMemberShare>> {
let selected_sessions = session_keys
.iter()
.map(String::as_str)
.collect::<BTreeSet<_>>();
let index_prefix = local_storage_key(INDEX_NAMESPACE);
let mut shares = BTreeMap::<String, SetMemberShare>::new();
for (local_key, value) in handle
.get_all_values(Some(&index_prefix))
.with_context(|| format!("failed to read GitMeta keys under '{index_prefix}'"))?
{
let MetaValue::Set(members) = value else {
bail!("existing GitMeta key '{local_key}' is not a set");
};
let Some(published_key) = strip_local_storage_prefix(&local_key) else {
continue;
};
let published_key = published_key.to_owned();
let selected_members = members
.into_iter()
.filter(|member| match serde_json::from_str::<IndexHit>(member) {
Ok(hit) => selected_sessions.contains(hit.session_key.as_str()),
Err(_) => false,
})
.collect::<Vec<_>>();
if selected_members.is_empty() {
continue;
}
shares.insert(
local_key.clone(),
SetMemberShare {View on GitHub (pinned to caf1f223d3)
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
Example fix
// before
let MetaValue::Set(members) = value else { bail!("...") };
// after: skip malformed local index keys instead of aborting the scan
let members = match value {
MetaValue::Set(members) => members,
_ => continue,
}; Defensive patterns
Strategy: validation
Validate before calling
// Pre-scan local index keys and report any non-Set members before publish
for (key, value) in handle.get_all_values(Some(&index_prefix))? {
if !matches!(value, MetaValue::Set(_)) {
eprintln!("malformed local index key: {key}");
}
} Type guard
fn local_index_is_set(v: &MetaValue) -> bool {
matches!(v, MetaValue::Set(_))
} Try / catch
let members = match value {
MetaValue::Set(members) => members,
_ => continue, // skip malformed local index keys
}; Prevention
- 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
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- existing GitMeta key '{associated_targets_key}' is not a str
- existing GitMeta key '{updated_at_key}' is not a string
- existing GitMeta key '{index_key}' is not a set
- existing GitMeta key '{associated_targets_key}' is not a str
- existing GitMeta key '{turns_key}' is not a list
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/6d4321843901dc01.
Report an issue: GitHub.