GitoxideLabs/gitoxide · error

only value and unspecified are possible here

Error message

only value and unspecified are possible here

What it means

This is a Rust `unreachable!()` panic in `gix-merge`'s merge-driver selection. The outer match on `attributes::StateRef` already filtered to only `Value` and `Unspecified` variants, so any other variant here indicates the enum grew new variants without updating this match — a broken internal invariant, not a user-triggerable condition.

Solutions

  1. Rebuild with consistent, semver-compatible versions of `gix-attributes` and `gix-merge` (run `cargo update -p gix-attributes` carefully and `cargo check`).
  2. Update `gix-merge` to a version matching the installed `gix-attributes` (both from the same release train).
  3. If you maintain the code, replace `unreachable!` with an explicit arm mapping the new variant to a driver or an error.
  4. Report the panic upstream with the attribute configuration that triggered the merge.

Example fix

// before
_ => unreachable!("only value and unspecified are possible here"),
// after
other => return Err(message!("unsupported attribute state {other:?} for merge driver"))
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure matching gix-merge / gix-attributes versions at build time
// cargo tree -i gix-attributes  // confirm a single, expected version

Try / catch

// Panics are not catchable safely in Rust; pin dependency versions.
// gix = { version = "X", exact = true } // avoid mixed gix-* versions
// Wrap merges in a subprocess (gix CLI) if panic isolation is required.

Prevention

When it happens

Trigger: Only triggered if the `gix_attributes::StateRef` enum gains a third variant (e.g. via a dependency upgrade of `gix-attributes`) while this match is not updated; effectively impossible on a consistent build of the crate.

Common situations: Hit during a merge that consults `merge` attributes to pick a merge driver when the compiled `gix-attributes` version disagrees with the code expectations; otherwise never seen in practice.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/c87916fd92af66c9. Report an issue: GitHub.

Appendix: source

Thrown at gix-merge/src/blob/platform/prepare_merge.rs:66

            .map_err(|err| Error::Attributes {
                source: err,
                kind: ResourceKind::CurrentOrOurs,
                rela_path: current.rela_path.clone(),
            })?;
        entry.matching_attributes(&mut self.attrs);
        let mut attrs = self.attrs.iter_selected();
        let merge_attr = attrs.next().expect("pre-initialized with 'merge'");
        let marker_size_attr = attrs.next().expect("pre-initialized with 'conflict-marker-size'");
        let mut driver = match merge_attr.assignment.state {
            attributes::StateRef::Set => DriverChoice::BuiltIn(BuiltinDriver::Text),
            attributes::StateRef::Unset => DriverChoice::BuiltIn(BuiltinDriver::Binary),
            attributes::StateRef::Value(_) | attributes::StateRef::Unspecified => {
                let name = match merge_attr.assignment.state {
                    attributes::StateRef::Value(name) => Some(name.as_bstr()),
                    attributes::StateRef::Unspecified => {
                        self.options.default_driver.as_ref().map(|name| name.as_bstr())
                    }
                    _ => unreachable!("only value and unspecified are possible here"),
                };
                self.find_driver_by_name(name)
            }
        };
        if let attributes::StateRef::Value(value) = marker_size_attr.assignment.state
            && let Some(value) = u8::from_str(value.as_bstr().to_str_lossy().as_ref())
                .ok()
                .and_then(NonZeroU8::new)
        {
            match &mut options.text.conflict {
                Conflict::Keep { marker_size, .. } => *marker_size = value,
                Conflict::ResolveWithOurs | Conflict::ResolveWithTheirs | Conflict::ResolveWithUnion => {}
            }
        }
        if let Some(recursive_driver_name) = match driver {
            DriverChoice::Index(idx) => self.drivers.get(idx),
            _ => None,
        }

View on GitHub (pinned to e73179060b)