zeroclaw-labs/zeroclaw · error
Composio execute failed on v3 ({v3_error_summary}){prime_suf
Error message
Composio execute failed on v3 ({v3_error_summary}){prime_suffix}{} What it means
Structured-parameter counterpart of the NLP failure: execute_action tried every slug candidate with the caller's params JSON against POST /tools/execute/{slug} and all attempts failed. v3_error_summary lists 'slug: error' per candidate, and a trailing Hint suggests action='list_accounts' when no connected_account_id was passed or auto-resolved. On this path the outer execute() additionally fetches the tool schema via get_tool_schema and appends an 'Expected input parameters:' block to ToolResult.error, so parameter-name mismatches are easy to spot.
Source
Thrown at crates/zeroclaw-tools/src/composio.rs:273
};
let prime_suffix = prime_error
.as_deref()
.map(|msg| format!(" ({msg})"))
.unwrap_or_default();
if text.is_some() {
anyhow::bail!(
"Composio v3 NLP execute failed on candidates ({v3_error_summary}){prime_suffix}{}",
build_connected_account_hint(
app_hint.as_deref(),
normalized_entity_id.as_deref(),
resolved_account_ref.as_deref(),
)
);
}
anyhow::bail!(
"Composio execute failed on v3 ({v3_error_summary}){prime_suffix}{}",
build_connected_account_hint(
app_hint.as_deref(),
normalized_entity_id.as_deref(),
resolved_account_ref.as_deref(),
)
);
}
fn build_v3_slug_candidates(&self, action_name: &str) -> Vec<String> {
let mut candidates = Vec::new();
let mut push_candidate = |candidate: String| {
if !candidate.is_empty() && !candidates.contains(&candidate) {
candidates.push(candidate);
}
};
if let Some(hit) = self.lookup_cached_action_slug(action_name) {View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the appended 'Expected input parameters' hint (or the per-candidate errors) and resend params with exactly those key names, filling every required field.
- Pass the exact slug as tool_slug taken from action='list' output instead of an alias.
- Run action='list_accounts' (app + entity_id): pass connected_account_id if an account exists, or run action='connect' first if the list is empty.
- Make sure entity_id matches the user_id the account was connected under.
- Fix the API key (401) or back off (429).
Example fix
// before: guessed param names
let args = json!({
"action": "execute",
"app": "gmail",
"action_name": "gmail_send_email",
"params": {"to": "a@b.c", "body_text": "hi"}
});
// after: exact slug + schema key names from action='list' [params: ...] hint
let args = json!({
"action": "execute",
"tool_slug": "gmail-send-email",
"params": {"recipient": "a@b.c", "body": "hi"},
"connected_account_id": "<from list_accounts>"
}); Defensive patterns
Strategy: try-catch
Validate before calling
// Validate param keys against the tool's published schema before executing
let actions = tool.list_actions(Some("gmail")).await?;
let action = actions
.iter()
.find(|a| a.name == "gmail-send-email")
.ok_or_else(|| anyhow::anyhow!("unknown action"))?;
if let Some(schema) = action.input_parameters.as_ref() {
let props = schema.get("properties").and_then(|v| v.as_object()).unwrap_or_default();
for key in params.as_object().unwrap().keys() {
if !props.contains_key(key) {
anyhow::bail!(
"param '{key}' not in schema; valid: {:?}",
props.keys().collect::<Vec<_>>()
);
}
}
} Try / catch
match tool.execute(args).await {
Ok(r) if r.success => { /* success */ }
Ok(r) => {
let e = r.error.unwrap_or_default();
if e.contains("execute failed on v3") {
// parse the 'Expected input parameters:' hint and self-correct params;
// if the trailing Hint mentions list_accounts, resolve the account instead
}
}
Err(e) => { /* transport error */ }
} Prevention
- Always source param names from action='list' [params: ...] output
- Pin tool_slug instead of sending aliases
- Pass connected_account_id once resolved and cache it per user/app
- Log the full ToolResult.error — it already embeds the schema hint
When it happens
Trigger: action='execute' with params whose keys do not match the tool's input schema (LLM-guessed names); missing required parameters; no connected account or an expired OAuth token for the entity; every slug candidate 404s (typos, renamed tools, stale cache); 401/429/5xx from Composio.
Common situations: Agent invents parameter names instead of using action='list' output; account connected under a different entity_id than the configured default; Composio renamed a tool so both the cached slug and spelling variants miss; free-tier rate limits hit mid-task.
Related errors
- Composio v3 NLP execute failed on candidates ({v3_error_summ
- Composio v3 action execution failed: {err}
- Composio v3 connected accounts lookup failed: {err}
- Composio v3 connect failed: {err}
- Composio v3 tool schema lookup failed for '{slug}': {err}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/5768437c71204217.
Report an issue: GitHub.