zeroclaw-labs/zeroclaw · error

Composio v3 NLP execute failed on candidates ({v3_error_summ

Error message

Composio v3 NLP execute failed on candidates ({v3_error_summary}){prime_suffix}{}

What it means

NLP-mode failure: execute_action was called with a natural-language 'text' argument (instead of structured params) and every slug candidate failed against POST /tools/execute/{slug}. v3_error_summary aggregates each attempt as 'slug: error | ...' using the per-candidate HTTP errors from execute_action_v3. prime_suffix is appended when the automatic action-list refresh also failed, and build_connected_account_hint appends a list_accounts suggestion when no connected_account_id was passed or auto-resolved. The outer execute() wrapper reports it as 'Action execution failed: ...' in ToolResult.error.

Source

Thrown at crates/zeroclaw-tools/src/composio.rs:263

            {
                Ok(result) => return Ok(result),
                Err(err) => v3_errors.push(format!("{slug}: {err}")),
            }
        }

        let v3_error_summary = if v3_errors.is_empty() {
            "no v3 candidates attempted".to_string()
        } else {
            v3_errors.join(" | ")
        };

        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(),
            )
        );
    }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Read v3_error_summary: each 'slug: HTTP ...' segment names the candidate tried and the server response — 404 means bad slug, 400 param problems, 401 bad key, 429 pacing.
  2. Run action='list_accounts' with the app and entity_id: if an account exists, pass its id as connected_account_id; if none, run action='connect', complete OAuth, and retry.
  3. Run action='list' with the app and pass the exact slug as tool_slug to skip candidate guessing.
  4. If NLP parameter resolution failed (400 param errors), switch from text to structured params using the listed [params: ...] key names.
  5. On 401/429, fix the API key or back off.

Example fix

// before: NLP mode, no pinned account
let args = json!({"action": "execute", "app": "github", "text": "star the repo zeroclaw/zeroclaw"});

// after: exact slug + structured params + explicit account
let args = json!({
    "action": "execute",
    "tool_slug": "github-star-repository", // exact slug from action='list'
    "params": {"owner": "zeroclaw", "repo": "zeroclaw"},
    "connected_account_id": "<id from action='list_accounts'>"
});
Defensive patterns

Strategy: fallback

Validate before calling

// Before NLP-mode execute, verify the user has a usable connected account
let accounts = tool
    .execute(json!({"action": "list_accounts", "app": "github", "entity_id": entity_id}))
    .await?;
let out = accounts.output.to_string();
if out.contains("No connected accounts") {
    anyhow::bail!("run action='connect' for 'github' before executing");
}

Try / catch

match tool.execute(args).await {
    Ok(r) if r.success => { /* done */ }
    Ok(r) => {
        let e = r.error.unwrap_or_default();
        if e.contains("NLP execute failed on candidates") {
            // fall back: pin tool_slug + structured params from action='list'
            // instead of retrying the same free-text call
        }
    }
    Err(e) => { /* transport failure */ }
}

Prevention

When it happens

Trigger: action='execute' with text set, where: no connected account exists for the (app, entity_id) pair; the account's OAuth token expired or was revoked; Composio's NLP could not resolve parameters from the text; every derived slug candidate (cache hit plus underscore/hyphen/case variants) 404s; the API key is invalid (401) or rate-limited (429).

Common situations: Agent executes before the user finished the OAuth connect flow; account connected under a different user_id than the entity_id in use (composio.entity_id default vs per-call entity_id); free-text commands for a tool that Composio renamed upstream; NLP-mode restrictions on the current Composio plan.

Related errors


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