jdx/mise · error

unsupported Git object id

Error message

unsupported Git object id: {commit}

What it means

`update_ref` in the history shadow repo only accepts Git object ids of SHA-1 (40 hex chars) or SHA-256 (64 hex chars) length before shelling out to `git update-ref`. Any other string — short hash, symbolic ref name, or empty/zero-length mismatch — is rejected with this error to avoid passing malformed ids to git.

Solutions

  1. Resolve the short hash or ref to a full object id first (`git rev-parse <ref>`) and pass the full 40/64-char id.
  2. Check the shadow repo's object format (core.repositoryformatversion / hash algorithm) to confirm it matches the id length being passed.
  3. Fix the caller that truncated or substituted the oid before reaching update_ref.

Example fix

// before
shadow.update_ref("refs/mise/history", &commit[..7], None)?;

// after
let full = shadow.git.run(PlumbingCall::new(["rev-parse", &commit[..7]]))?.trim().to_string();
shadow.update_ref("refs/mise/history", &full, None)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_full_oid(s: &str) -> bool {
    (s.len() == 40 || s.len() == 64) && s.chars().all(|c| c.is_ascii_hexdigit())
}

Prevention

When it happens

Trigger: Calling `update_ref(name, commit, expected)` with a `commit` string whose length is not 40 or 64 — e.g. a 7-char short hash, a full ref name like `refs/heads/main`, or a corrupted oid from a parsed log.

Common situations: Downstream code stored a shortened commit hash from user input or display output; a repo configured for an unexpected hash algorithm produced ids of a different length; a test or script passed a placeholder value.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/7f0502cd5b9810bd. Report an issue: GitHub.

Appendix: source

Thrown at src/system/history/shadow.rs:1487

        let mut args = vec!["commit-tree".to_string(), tree.to_string()];
        for parent in parents {
            args.push("-p".to_string());
            args.push(parent.to_string());
        }
        args.push("-m".to_string());
        args.push(message.to_string());
        self.output_str(PlumbingCall::new(args))
    }

    /// Moves `name` to `commit` only if it still points at `expected`
    /// (`None`: must not exist).
    pub(crate) fn update_ref(
        &self,
        name: &str,
        commit: &str,
        expected: Option<&str>,
    ) -> Result<()> {
        eyre::ensure!(
            matches!(commit.len(), 40 | 64),
            "unsupported Git object id: {commit}"
        );
        let zero = "0".repeat(commit.len());
        self.git.run(PlumbingCall::new([
            "update-ref",
            name,
            commit,
            expected.unwrap_or(&zero),
        ]))
    }

    /// Deletes a ref if it exists.
    pub(crate) fn delete_ref(&self, name: &str) -> Result<()> {
        if self.ref_oid(name)?.is_some() {
            self.git
                .run(PlumbingCall::new(["update-ref", "-d", name]))?;
        }

View on GitHub (pinned to 533346cc37)