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

AcpChannel does not support reactions

Error message

AcpChannel does not support reactions

What it means

ACP renders agent output as streamed message chunks and has no per-message reaction primitive, so add_reaction always returns an error. ZeroClaw refuses to silently no-op (the trait default would report success), so the reaction tool's caller learns the truth that the reaction cannot be delivered on this channel.

Solutions

  1. Gate the reaction tool by channel capability — skip or short-circuit it when the channel is ACP.
  2. Replace the reaction with a text acknowledgement sent via Channel::send, which ACP supports as an agent_message_chunk.
  3. Catch the error and tell the agent reactions are unsupported so it picks a different affordance.

Example fix

// before
ch.add_reaction(channel_id, message_id, "+1").await?;

// after
if ch.name() == "acp" {
    ch.send(&SendMessage::new("ack: done", recipient)).await?;
} else {
    ch.add_reaction(channel_id, message_id, "+1").await?;
}
Defensive patterns

Strategy: validation

Validate before calling

fn supports_reactions(ch: &dyn Channel) -> bool {
    // ACP has no per-message reaction primitive; add_reaction fails by design.
    ch.name() != "acp"
}

Type guard

fn is_reaction_capable(ch: &dyn Channel) -> bool {
    ch.name() != "acp"
}

Prevention

When it happens

Trigger: The agent invokes the reaction tool (attach an emoji to a message) while the active channel is the ACP back-channel — i.e., during a session driven from an ACP editor/orchestrator client.

Common situations: Prompts and skills written for chat channels (Slack-style emoji acknowledgements) reused verbatim in ACP sessions; agent loops that add a reaction after every tool result.

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 zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/4f880c3ed7a0d070. Report an issue: GitHub.

Appendix: source

Thrown at crates/zeroclaw-channels/src/acp_channel.rs:327

            "AcpChannel.listen is not supported (free-form ask_user awaits ACP elicitation Phase 2)"
        )
    }

    fn supports_free_form_ask(&self) -> bool {
        false
    }

    async fn add_reaction(
        &self,
        _channel_id: &str,
        _message_id: &str,
        _emoji: &str,
    ) -> anyhow::Result<()> {
        // ACP renders agent output as message chunks — there's no per-message
        // reaction primitive in the protocol, so silently no-oping (the trait
        // default) would falsely report success to the agent. Surface as Err
        // so the `reaction` tool's caller sees the truth.
        anyhow::bail!("AcpChannel does not support reactions")
    }

    async fn remove_reaction(
        &self,
        _channel_id: &str,
        _message_id: &str,
        _emoji: &str,
    ) -> anyhow::Result<()> {
        anyhow::bail!("AcpChannel does not support reactions")
    }

    async fn request_choice(
        &self,
        question: &str,
        choices: &[String],
        timeout: Duration,
    ) -> anyhow::Result<Option<String>> {
        if choices.is_empty() {

View on GitHub (pinned to 88bb9c8533)