gitbutlerapp/gitbutler · error
existing GitMeta key '{associated_targets_key}' is not a str
Error message
existing GitMeta key '{associated_targets_key}' is not a string What it means
Each session stores its observed branch/review/change associations as a JSON blob in the `:associated-targets` key, which must be a `MetaValue::String` deserializable into `StoredSessionAssociations`. The read path that decides whether a session observes a target bails when the key exists but is not a String. This is a shape check on stored JSON-in-a-string data.
Source
Thrown at crates/but-agentlog/src/gitmeta/read.rs:263
fn session_associations_observe_target(
handle: &SessionTargetHandle<'_>,
session_key: &str,
status: PublicationStatus,
target: RelatedTarget<'_>,
) -> Result<bool> {
let associated_targets_key = format!(
"{}:associated-targets",
session_storage_prefix(status, session_key)
);
let Some(value) = handle
.get_value(&associated_targets_key)
.with_context(|| format!("failed to read GitMeta key '{associated_targets_key}'"))?
else {
return Ok(false);
};
let MetaValue::String(value) = value else {
bail!("existing GitMeta key '{associated_targets_key}' is not a string");
};
let targets: StoredSessionAssociations = serde_json::from_str(&value).with_context(|| {
format!("existing GitMeta key '{associated_targets_key}' has invalid JSON")
})?;
Ok(targets.observes(target))
}
#[derive(Deserialize)]
struct StoredSessionAssociations {
#[serde(default)]
branches: BTreeSet<String>,
#[serde(default)]
reviews: BTreeSet<String>,
#[serde(default)]
changes: BTreeSet<String>,
}
impl StoredSessionAssociations {View on GitHub (pinned to caf1f223d3)
Solutions
- Run `but agentlog sync` to fetch consistent state, then retry
- Re-capture or re-publish the session (hook + publish) so the associations key is rewritten in the current string format
- Align `but` versions across machines that sync the same GitMeta remote
- As a last resort, delete the malformed `:associated-targets` key — the read path treats absence as 'observes nothing'
Example fix
// before
let observes = session_observes(&handle, status, session_key, target)?;
// after: absence and malformed both mean 'no association'
let observes = match session_observes(&handle, status, session_key, target) {
Ok(v) => v,
Err(err) if err.to_string().contains("associated-targets") => false,
Err(err) => return Err(err),
}; Defensive patterns
Strategy: type-guard
Validate before calling
// Verify the associations key parses before relying on related-session checks
let key = format!("{session_prefix}:associated-targets");
if let Some(MetaValue::String(raw)) = handle.get_value(&key)? {
serde_json::from_str::<StoredSessionAssociations>(&raw)?; // fail early with context
} Type guard
fn associations_are_valid(v: Option<&MetaValue>) -> bool {
match v {
Some(MetaValue::String(s)) => serde_json::from_str::<StoredSessionAssociations>(s).is_ok(),
_ => false,
}
} Try / catch
match session_observes_target(&handle, status, session_key, target) {
Ok(v) => v,
Err(err) if err.to_string().contains("associated-targets") => false,
Err(err) => return Err(err),
} Prevention
- Keep association data written only via publish/hook flows
- Re-publish sessions after version upgrades
- Do not delete individual association fields from GitMeta by hand
When it happens
Trigger: Related-session lookups and skim outlines calling `turn_detail_observes_target`/association checks for `gitbutler:agent-session:<status>:<key>:associated-targets` when that key holds a Set or List variant instead of the serialized JSON string.
Common situations: Writer version skew changing how associations are stored; a session partially migrated between formats; GitMeta merge/resolution producing a non-string value; external tooling overwriting the key.
Related errors
- existing GitMeta key '{detail_key}' is not a string
- 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 '{turns_key}' is not a list
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/10e60c56e1891ad2.
Report an issue: GitHub.