gitbutlerapp/gitbutler · error
existing GitMeta key '{index_key}' is not a set
Error message
existing GitMeta key '{index_key}' is not a set What it means
but-agentlog keeps per-status index keys (built by `status_index_key`, one per branch/review/change target) whose value must be a `MetaValue::Set` of JSON-serialized `IndexHit` entries pointing at sessions. When reading the index for a related target, a value of any other MetaValue variant triggers this bail. It signals the index key exists but was stored with the wrong shape.
Source
Thrown at crates/but-agentlog/src/gitmeta/read.rs:205
}
})
.collect())
}
fn target_index_hits(
handle: &SessionTargetHandle<'_>,
target: RelatedTarget<'_>,
status: PublicationStatus,
) -> Result<BTreeSet<String>> {
let index_key = status_index_key(status, target.index_kind(), target.key());
let Some(value) = handle
.get_value(&index_key)
.with_context(|| format!("failed to read GitMeta key '{index_key}'"))?
else {
return Ok(BTreeSet::new());
};
let MetaValue::Set(index_hits) = value else {
bail!("existing GitMeta key '{index_key}' is not a set");
};
Ok(index_hits)
}
fn turn_detail_observes_target(
handle: &SessionTargetHandle<'_>,
hit: &IndexHit,
target: RelatedTarget<'_>,
status: PublicationStatus,
session_activity_matches: &mut BTreeMap<String, bool>,
) -> Result<bool> {
let detail_key = format!(
"{}:turn:{}",
session_storage_prefix(status, &hit.session_key),
hit.turn_key
);
let Some(detail) = read_optional_turn_detail(handle, &detail_key)? else {
return Ok(false);View on GitHub (pinned to caf1f223d3)
Solutions
- Run `but agentlog sync` and retry the skim/publish — a clean pull often replaces the malformed index
- Align all machines on one `but` version so one writer shape is used, then re-publish the target to rewrite the index key
- Inspect the GitMeta ref history for the index key and restore the last version that was a Set
- Delete the malformed index key (listings degrade to 'no related sessions' until re-published) rather than aborting every read
Example fix
// before
let hits = index_hits(&handle, target, status)?; // bails on wrong variant
// after: treat a wrongly-shaped index as empty
let hits = match index_hits(&handle, target, status) {
Ok(hits) => hits,
Err(err) if err.to_string().contains("is not a set") => BTreeSet::new(),
Err(err) => return Err(err),
}; Defensive patterns
Strategy: type-guard
Validate before calling
// Pre-check the index key's variant before skim/publish
let index_key = status_index_key(status, kind, target_key);
if let Some(value) = handle.get_value(&index_key)? {
if !matches!(value, MetaValue::Set(_)) {
// malformed index; skip or repair before calling skim
}
} Type guard
fn index_is_set(v: &MetaValue) -> bool {
matches!(v, MetaValue::Set(_))
} Try / catch
match index_hits(&handle, target, status) {
Ok(hits) => process(hits),
Err(err) if err.to_string().contains("is not a set") => {
eprintln!("index for target is malformed; treating as empty")
}
Err(err) => return Err(err),
} Prevention
- Re-publish a target after upgrading but-agentlog to rewrite its index keys
- Avoid mixing but versions that sync the same metadata remote
- Treat index keys as but-agentlog-owned; never write them directly
When it happens
Trigger: `but agentlog skim branch <name>` / `skim review <id>` / `skim change <id>`, or `publish <target>`, reading `status_index_key(status, kind, key)` when that key holds a String or List instead of a Set of IndexHit JSON strings.
Common situations: Index key written by an older/newer but-agentlog with a different encoding; GitMeta push-conflict resolutions merging keys of mixed shapes; manual edits or third-party tools writing the index key; partial migration leaving a stale index value.
Related errors
- existing GitMeta key '{transcript_key}' is not a list
- existing GitMeta key '{updated_at_key}' is not a string
- existing GitMeta key '{associated_targets_key}' is not a str
- existing GitMeta key '{turns_key}' is not a list
- existing GitMeta key '{detail_key}' is not a string
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/fad74aa46bd80bdc.
Report an issue: GitHub.