zeroclaw-labs/zeroclaw · error · anyhow::Error

elicitation returned unknown choice const: {const_value}

Error message

elicitation returned unknown choice const: {const_value}

What it means

Phase 6 of `zeroclaw update` (src/commands/update.rs:292) — after the new binary is swapped in, smoke_test runs `<exe> --version`; a spawn failure or non-zero exit triggers rollback_binary to restore the Phase-3 `<exe>.bak` backup, then this bail. The system is left on the previous, working version. It means the downloaded binary passed download and validation (size, architecture, --version on the staged copy in Phase 4) but fails to start from its final installed location.

Source

Thrown at crates/zeroclaw-api/src/elicitation.rs:213

/// Decode the accepted `content` payload of an `elicitation/create`
/// single-select response back into the original display text.
///
/// Expects `content.choice` to be a `"choice-<idx>"` string whose
/// index is in bounds against `choices`. Returns the original text.
/// Returns `Err` if the field is missing, malformed, or out of range —
/// the same defense-in-depth posture the RFD recommends.
pub fn decode_single_select_accept(content: &Value, choices: &[String]) -> anyhow::Result<String> {
    let const_value = content
        .get("choice")
        .and_then(|v| v.as_str())
        .ok_or_else(|| anyhow::Error::msg("elicitation accept missing content.choice string"))?;
    let idx = const_value
        .strip_prefix("choice-")
        .and_then(|s| s.parse::<usize>().ok());
    match idx.and_then(|i| choices.get(i)) {
        Some(text) => Ok(text.clone()),
        None => anyhow::bail!("elicitation returned unknown choice const: {const_value}"),
    }
}

/// Decode the accepted `content` payload of an `elicitation/create`
/// multi-select response back into the original display texts.
pub fn decode_multi_select_accept(
    content: &Value,
    choices: &[String],
) -> anyhow::Result<Vec<String>> {
    let arr = content
        .get("choices")
        .and_then(|v| v.as_array())
        .ok_or_else(|| anyhow::Error::msg("elicitation accept missing content.choices array"))?;
    let mut out = Vec::with_capacity(arr.len());
    for v in arr {
        let s = v
            .as_str()
            .ok_or_else(|| anyhow::Error::msg("non-string entry in content.choices"))?;

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Confirm you are still on the old version (`zeroclaw --version`) — the rollback already restored it
  2. Reproduce the real startup error: download the release archive manually, run the extracted binary's --version directly, and check dynamic linking (ldd on Linux)
  3. If the prebuilt binary is incompatible with your system (glibc/runtime), install from source: ./install.sh --source (or --preset full / --features channels-full as needed)
  4. If the binary is genuinely broken on all hosts, report the release with the startup error and stay on your current version until a fixed release ships

Example fix

# before
$ zeroclaw update
Error: Update rolled back — smoke test failed: smoke test: updated binary returned non-zero exit code

# after
$ zeroclaw --version              # still on the old (rolled-back) version
$ # reproduce the real startup failure of the new binary:
$ curl -fsSL <release-url>/zeroclaw-x86_64-unknown-linux-gnu.tar.gz -o /tmp/zc.tgz
$ tar xzf /tmp/zc.tgz -C /tmp && ldd /tmp/zeroclaw | grep 'not found'
$ ./install.sh --source          # build locally if the prebuilt binary is incompatible
Defensive patterns

Strategy: fallback

Try / catch

if let Err(e) = update::run(version, force).await {
    if e.to_string().contains("Update rolled back — smoke test failed") {
        // Old version already restored. Verify with `zeroclaw --version`,
        // keep the deployment pinned on the current version, and either
        // install from source (./install.sh --source) or wait for a fixed
        // release. Do not retry the same prebuilt artifact endlessly.
    }
}

Prevention

When it happens

Trigger: `zeroclaw update` where the newly swapped binary exits non-zero or cannot be executed in place: host linker/runtime incompatibility (binary built against a newer glibc), missing shared library or VC/UCRT runtime, macOS Gatekeeper/quarantine blocking the replaced binary, or a broken release build that only fails at runtime.

Common situations: Prebuilt linux-gnu binary on an older distro (glibc too old); missing Visual C++ redistributable on Windows; Gatekeeper quarantine on macOS; a release whose binary was miscompiled or stripped of a needed dependency.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/0cfe08d7cf9cc555. Report an issue: GitHub.