gitbutlerapp/gitbutler · error

existing GitMeta key '{sources_key}' is not a set

Error message

existing GitMeta key '{sources_key}' is not a set

What it means

The PR projection reads each session's `:sources` key (e.g. `gitbutler:agent-session:<key>:sources`) as a `MetaValue::Set` of source identifiers, then reads per-source label keys. A missing key means no sources; an existing key that is not a Set bails, aborting the whole projection for the requested sessions.

Source

Thrown at crates/but-agentlog/src/projection.rs:714

fn session_source_metadata<'a>(
    repo_path: &Path,
    session_keys: impl IntoIterator<Item = &'a String>,
) -> Result<BTreeMap<String, Vec<ProjectionAgentLabel>>> {
    let gitmeta = Session::open(repo_path).context("failed to open GitMeta session")?;
    let target = Target::project();
    let handle = gitmeta.target(&target);
    let mut output = BTreeMap::new();
    for session_key in session_keys {
        let session_prefix = format!("gitbutler:agent-session:{session_key}");
        let sources_key = format!("{session_prefix}:sources");
        let sources = match handle
            .get_value(&sources_key)
            .with_context(|| format!("failed to read GitMeta key '{sources_key}'"))?
        {
            None => BTreeSet::new(),
            Some(MetaValue::Set(values)) => values.into_iter().collect(),
            Some(_) => bail!("existing GitMeta key '{sources_key}' is not a set"),
        };
        let mut labels = Vec::new();
        for source_key in sources {
            let source_prefix = format!("{session_prefix}:source:{source_key}");
            let label = ProjectionAgentLabel {
                agent: optional_string_value(&handle, &format!("{source_prefix}:agent"))?,
                provider: optional_string_value(&handle, &format!("{source_prefix}:provider"))?,
                model: optional_string_value(&handle, &format!("{source_prefix}:model"))?,
                tool_version: optional_string_value(
                    &handle,
                    &format!("{source_prefix}:tool-version"),
                )?,
            };
            if label.agent.is_some() || label.provider.is_some() || label.model.is_some() {
                labels.push(label);
            }
        }
        labels.sort_by(|lhs, rhs| {

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Run `but agentlog sync` and retry the projection
  2. Re-capture the affected sessions under the current `but` build so `:sources` is rewritten as a Set
  3. Align `but` versions across all machines contributing agentlog data
  4. Restore the last Set-valued key from GitMeta history or delete it (absence reads as 'no sources')

Example fix

// before
Some(_) => bail!("existing GitMeta key '{sources_key}' is not a set"),

// after: treat a malformed sources key as no sources
let sources = match handle.get_value(&sources_key)? {
    Some(MetaValue::Set(values)) => values.into_iter().collect(),
    _ => BTreeSet::new(),
};
Defensive patterns

Strategy: type-guard

Validate before calling

// Before projecting, verify each session's sources key variant
if let Some(value) = handle.get_value(&sources_key)? {
    if !matches!(value, MetaValue::Set(_)) { /* skip session in this projection */ }
}

Type guard

fn sources_is_set(v: Option<&MetaValue>) -> bool {
    matches!(v, Some(MetaValue::Set(_)))
}

Try / catch

let sources = match handle.get_value(&sources_key)? {
    Some(MetaValue::Set(values)) => values.into_iter().collect(),
    _ => BTreeSet::new(),
};

Prevention

When it happens

Trigger: Building a projection over sessions where one session's `:sources` key holds a String or List — e.g. state written by an incompatible but-agentlog version or mangled via a metadata merge.

Common situations: Mixed `but` versions across contributor machines pushing to the same GitMeta remote; projections run over sessions captured by pre-release builds; manual key edits.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/2f6e1e0f71163d3e. Report an issue: GitHub.