AprilNEA/OpenLogi · error

unsupported contribution state version

Error message

unsupported contribution state version {}

What it means

When finishing a contribution, the persisted contribution state file carries a version field that must equal the CLI's current `STATE_VERSION`. An unknown/older version means the state was written by a different (older or newer) tool version and cannot safely be resumed. `validate_state` rejects it before `finish` proceeds.

Solutions

  1. Use the same CLI version that started the contribution to run the finish step.
  2. Delete the in-progress output directory and restart the contribution from scratch with the current CLI.
  3. Inspect the state file's `version` field and, if a stale artifact, remove it; do not hand-edit the version to force a match.

Example fix

// before (state from older CLI)
openlogi fixture contribute finish --id mx-master ...
// after
rm -rf out/mx-master && openlogi fixture contribute --id mx-master --name "MX Master" --output out/mx-master  # restart with current CLI
Defensive patterns

Strategy: fallback

Validate before calling

version=$(python3 -c "import json;print(json.load(open('out/$ID/state.json'))['version'])") && [ "$version" = "1" ] || echo "state version mismatch: use the originating CLI version"

Try / catch

match finish_contribution() {
    Err(e) if e.to_string().contains("unsupported contribution state version") => {
        // restart the contribution with the current CLI
    }
    other => other?,
}

Prevention

When it happens

Trigger: Run the `finish` step of `openlogi fixture contribute` against a state file produced by an older or newer OpenLogi CLI whose STATE_VERSION differs. Happens after upgrading/downgrading the CLI, or mixing two installs.

Common situations: Upgrading the CLI mid-contribution; checking out an older branch and finishing a state created on a newer one; a corrupted state file whose version field was hand-edited.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13). Data as JSON: /api/errors/d0c2b5b1f7741604. Report an issue: GitHub.

Appendix: source

Thrown at crates/openlogi-cli/src/cmd/fixture/contribute.rs:466

    }
    if Path::new(&args.id).file_name() != Some(OsStr::new(&args.id))
        || args.id.contains('/')
        || args.id.contains('\\')
    {
        bail!("--id must be one synthetic path component without separators");
    }
    if args.name.trim().is_empty() {
        bail!("--name must be a nonempty synthetic device name");
    }
    if args.output.file_name() != Some(OsStr::new(&args.id)) {
        bail!("--output directory name must exactly equal --id");
    }
    Ok(())
}

fn validate_state(args: &ContributeArgs, state: &ContributionState) -> Result<()> {
    if state.version != STATE_VERSION {
        bail!("unsupported contribution state version {}", state.version);
    }
    if state.fixture_id != args.id
        || state.profile_id != format!("{}-profile", args.id)
        || state.profile_name != args.name
    {
        bail!("--id and --name must match the in-progress contribution");
    }
    Ok(())
}

fn read_json<T: serde::de::DeserializeOwned>(path: &Path, asset: &str) -> Result<T> {
    let bytes = fs::read(path).with_context(|| format!("could not read {asset}"))?;
    serde_json::from_slice(&bytes).with_context(|| format!("could not parse {asset}"))
}

fn require_directory(path: &Path, asset: &str) -> Result<()> {
    let metadata =
        fs::symlink_metadata(path).with_context(|| format!("could not inspect {asset}"))?;

View on GitHub (pinned to e846e6f4b4)