zeroclaw-labs/zeroclaw · warning

RPC elicitation/create timed out after {timeout:?}

Error message

RPC elicitation/create timed out after {timeout:?}

What it means

The elicitation approval path wraps the rpc.request("elicitation/create", ...) future in tokio::time::timeout with a caller-supplied duration. If the operator never answers within that window, the timeout arm bails with the elapsed duration. This is an expected operational outcome — an unanswered prompt — distinct from error 878 where the RPC itself errored.

Source

Thrown at crates/zeroclaw-runtime/src/rpc/approval_channel.rs:239

    ) -> anyhow::Result<Option<String>> {
        let req = ElicitationRequest {
            session_id: self.session_id.clone(),
            mode: ElicitationMode::Form,
            message: question.to_string(),
            requested_schema: single_select_schema(choices),
        };
        debug_assert!(
            matches!(req.mode, ElicitationMode::Form),
            "Phase 1 must not emit URL-mode elicitation"
        );
        let params = serde_json::to_value(&req)?;
        let call = self.rpc.request("elicitation/create", params);
        let response_value = match tokio::time::timeout(timeout, call).await {
            Ok(Ok(value)) => value,
            Ok(Err(e)) => {
                anyhow::bail!("RPC elicitation/create failed: {} ({})", e.message, e.code)
            }
            Err(_) => anyhow::bail!("RPC elicitation/create timed out after {timeout:?}"),
        };
        let parsed: ElicitationResponse = serde_json::from_value(response_value)
            .map_err(|e| anyhow::Error::msg(format!("malformed elicitation response: {e}")))?;
        match parsed {
            ElicitationResponse::Accept { content } => {
                let text = decode_single_select_accept(&content, choices)?;
                Ok(Some(text))
            }
            ElicitationResponse::Decline | ElicitationResponse::Cancel => Ok(None),
        }
    }

    /// Form-mode elicitation multi-select path — same wire shape as
    /// `AcpChannel::request_multi_choice`.
    async fn request_multi_choice_via_elicitation(
        &self,
        question: &str,
        choices: &[String],

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Raise the elicitation/approval timeout configuration to match realistic human response time for the deployment
  2. Verify the client actually surfaces the prompt (check notification settings, visible session)
  3. Design callers to treat timeout as non-consent: catch this bail and take the safe default/deny path
  4. For unattended flows, pre-configure auto-approval policies so human prompts never block

Example fix

// before: timeout treated as a hard error
let ans = channel.request_choice(&q, &choices, Duration::from_secs(30)).await?;

// after: timeout degrades to deny
match channel.request_choice(&q, &choices, Duration::from_secs(120)).await {
    Ok(Some(c)) => c,
    other => { tracing::warn!("no operator answer, denying"); deny() }
}
Defensive patterns

Strategy: fallback

Try / catch

match channel.request_choice(&q, &choices, timeout).await {
    Ok(Some(c)) => c,
    Ok(None) => default_choice(),
    Err(e) if e.to_string().contains("timed out") => {
        // operator absent: take the safe default/deny and continue — never block the runtime
        default_choice()
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Operator is away or misses the prompt before the timeout expires; the client renders the elicitation form but nobody interacts; timeout configured too aggressively for human response times; UI swallowed the prompt (notification lost, window hidden) so no answer ever arrives.

Common situations: Unattended automation hitting approval gates; timeouts tuned for fast acks applied to rare high-stakes approvals; first-time users unfamiliar with the prompt UI; long-running sessions where prompts queue behind other activity.

Understand the failure class

Related errors


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