{"record":{"id":"10e60c56e1891ad2","repo":"gitbutlerapp/gitbutler","slug":"existing-gitmeta-key-associated-targets-key-is","errorCode":null,"errorMessage":"existing GitMeta key '{associated_targets_key}' is not a string","messagePattern":"existing GitMeta key '(.+?)' is not a string","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-agentlog/src/gitmeta/read.rs","lineNumber":263,"sourceCode":"\nfn session_associations_observe_target(\n    handle: &SessionTargetHandle<'_>,\n    session_key: &str,\n    status: PublicationStatus,\n    target: RelatedTarget<'_>,\n) -> Result<bool> {\n    let associated_targets_key = format!(\n        \"{}:associated-targets\",\n        session_storage_prefix(status, session_key)\n    );\n    let Some(value) = handle\n        .get_value(&associated_targets_key)\n        .with_context(|| format!(\"failed to read GitMeta key '{associated_targets_key}'\"))?\n    else {\n        return Ok(false);\n    };\n    let MetaValue::String(value) = value else {\n        bail!(\"existing GitMeta key '{associated_targets_key}' is not a string\");\n    };\n    let targets: StoredSessionAssociations = serde_json::from_str(&value).with_context(|| {\n        format!(\"existing GitMeta key '{associated_targets_key}' has invalid JSON\")\n    })?;\n    Ok(targets.observes(target))\n}\n\n#[derive(Deserialize)]\nstruct StoredSessionAssociations {\n    #[serde(default)]\n    branches: BTreeSet<String>,\n    #[serde(default)]\n    reviews: BTreeSet<String>,\n    #[serde(default)]\n    changes: BTreeSet<String>,\n}\n\nimpl StoredSessionAssociations {","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-agentlog/src/gitmeta/read.rs#L245-L281","documentation":"session_associations_observe_target reads the session's associated-targets key, expected to be a MetaValue::String containing JSON (StoredSessionAssociations). If the key exists but holds another MetaValue variant, the stored shape is invalid and the function bails. An absent key is fine (returns false); only a present-but-wrongly-typed value triggers this error.","triggerScenarios":"turn_detail_observes_target -> session_associations_observe_target when handle.get_value(associated_targets_key) returns Some(value) that is not MetaValue::String — the associations key was overwritten with a non-string value.","commonSituations":"Writer bug storing a set/list of targets instead of the JSON string; older or newer tool versions with different storage schemas sharing the repo; manual GitMeta edits; corrupted storage.","solutions":["Delete the invalid key and re-record the session associations (writer serializes StoredSessionAssociations as JSON)","Fix the writer path to always store serde_json::to_string(&StoredSessionAssociations) as a string","Check which tool/version wrote the key and align reader/writer schemas","Rebuild the GitMeta data for the session if more keys are misshapen"],"exampleFix":"// before\nhandle.set_value(&associated_targets_key, MetaValue::List(entries));\n// after\nlet json = serde_json::to_string(&StoredSessionAssociations::from(entries))?;\nhandle.set_value(&associated_targets_key, MetaValue::String(json));","handlingStrategy":"validation","validationCode":"let v = gitmeta_get(&repo_path, &associated_targets_key);\nlet ok = matches!(v, None | Some(MetaValue::String(s)) if serde_json::from_str::<StoredSessionAssociations>(&s).is_ok());\nif !ok { /* repair before reading associations */ }","typeGuard":"fn is_valid_associations(v: Option<&MetaValue>) -> bool {\n    match v {\n        None => true,\n        Some(MetaValue::String(s)) => serde_json::from_str::<StoredSessionAssociations>(s).is_ok(),\n        _ => false,\n    }\n}","tryCatchPattern":"match session_associations_observe_target(handle, target) {\n    Ok(observes) => observes,\n    Err(e) if e.to_string().contains(\"is not a string\") => {\n        handle.delete_value(&associated_targets_key);\n        false\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Serialize StoredSessionAssociations with serde_json and store as MetaValue::String only","Keep writer and reader schema versions in sync","Never overwrite associations keys with structured MetaValue variants","Add a repair pass that drops invalid association keys"],"tags":["gitmeta","type-mismatch","json","schema"],"backgroundTag":"type-mismatch","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}