gitbutlerapp/gitbutler · error
existing GitMeta key '{detail_key}' is missing
Error message
existing GitMeta key '{detail_key}' is missing What it means
`read_turn_detail` requires the per-turn detail key `<session_prefix>:turn:<turn_key>` to exist; unlike its `read_optional_turn_detail` sibling it does not tolerate absence. The bail fires when the turns list or index references a turn whose detail record is not present in GitMeta. That indicates a torn or partially-synced state between the turn list and the turn detail records.
Source
Thrown at crates/but-agentlog/src/gitmeta/read_support.rs:45
};
let MetaValue::List(turn_entries) = turns_value else {
bail!("existing GitMeta key '{turns_key}' is not a list");
};
let summaries = stored_turn_summary_entries(turn_entries, turns_key)?
.into_iter()
.map(|entry| entry.summary)
.collect::<Vec<_>>();
Ok(summaries)
}
pub(super) fn read_turn_detail(
handle: &SessionTargetHandle<'_>,
detail_key: &str,
) -> Result<StoredTurnDetail> {
let Some(detail) = read_optional_turn_detail(handle, detail_key)? else {
bail!("existing GitMeta key '{detail_key}' is missing");
};
Ok(detail)
}
pub(super) fn read_optional_turn_detail(
handle: &SessionTargetHandle<'_>,
detail_key: &str,
) -> Result<Option<StoredTurnDetail>> {
let Some(value) = handle
.get_value(detail_key)
.with_context(|| format!("failed to read GitMeta key '{detail_key}'"))?
else {
return Ok(None);
};
let MetaValue::String(detail) = value else {
bail!("existing GitMeta key '{detail_key}' is not a string");
};
serde_json::from_str(&detail)View on GitHub (pinned to caf1f223d3)
Solutions
- Run `but agentlog sync` to complete the partial state and retry the exact turn key
- Re-run capture for the session (let the agent produce one more turn, then hook + publish) so details are rewritten
- Verify the turn key from `show <session>` output and retry with the exact `--turn` value — stale keys from an older turns list are a common cause
- If the detail is unrecoverable, delete the stale entry from the `:turns` list or the whole session and re-capture
Example fix
// before
let detail = read_turn_detail(&handle, &detail_key)?;
// after: prefer the optional reader and handle absence explicitly
let detail = match read_optional_turn_detail(&handle, &detail_key)? {
Some(detail) => detail,
None => bail!("turn '{detail_key}' has no stored detail; re-run `but agentlog sync`")
}; Defensive patterns
Strategy: validation
Validate before calling
// Verify the turn detail key exists before requesting it
let detail_key = format!("{session_prefix}:turn:{turn_key}");
if handle.get_value(&detail_key)?.is_none() {
eprintln!("turn {turn_key} detail not synced yet; run `but agentlog sync`");
} Type guard
fn turn_detail_exists(handle: &SessionTargetHandle<'_>, key: &str) -> Result<bool> {
Ok(handle.get_value(key)?.is_some())
} Try / catch
match read_optional_turn_detail(&handle, &detail_key)? {
Some(detail) => detail,
None => { /* sync and retry, or surface 'turn detail unavailable' */ }
} Prevention
- Do not interrupt publish mid-run; a torn turns/detail state is the main cause
- Run sync after any failed publish before reading turns
- Read turn keys from a fresh `show` output, not from stale UI state
When it happens
Trigger: `but agentlog show <session> --turn <turn_key>` (and record-reassembly paths) where `:turns` lists the turn but `:turn:<turn_key>` is absent — e.g. a publish that wrote the turns list but not every detail key, or a partial pull/sync.
Common situations: Interrupted publish or sync (network dropped mid-push); GitMeta push-conflict resolution that dropped detail keys; reading a session captured by an older writer that did not persist turn details; concurrent capture and publish racing on the same session.
Related errors
- existing GitMeta key '{transcript_key}' is missing
- existing GitMeta key '{detail_key}' is not a string
- existing GitMeta key '{detail_key}' is not a string
- existing GitMeta key '{updated_at_key}' is not a string
- existing GitMeta key '{index_key}' is not a set
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/0b8c15b3981e441b.
Report an issue: GitHub.