tinyhumansai/openhuman · error · anyhow::Error
composio.execute_tool: tool slug must not be empty
Error message
composio.execute_tool: tool slug must not be empty
What it means
ComposioClient::execute_tool rejects a tool slug that is empty after trimming, before the egress descriptor is built and the POST /agent-integrations/composio/execute request is sent. The guard runs before privacy disclosure (emit_external_transfer) so a blank slug never counts as an external transfer.
Source
Thrown at src/openhuman/integrations/composio/client.rs:192
} else {
format!("/agent-integrations/composio/tools?{}", params.join("&"))
};
tracing::debug!(path = %path, "[composio] list_tools");
self.inner.get::<ComposioToolsResponse>(&path).await
}
// ── Execute ─────────────────────────────────────────────────────
/// `POST /agent-integrations/composio/execute` — run a Composio
/// action and return the provider result + cost.
pub async fn execute_tool(
&self,
tool: &str,
arguments: Option<serde_json::Value>,
) -> Result<ComposioExecuteResponse> {
let tool = tool.trim();
if tool.is_empty() {
anyhow::bail!("composio.execute_tool: tool slug must not be empty");
}
// Egress spine (privacy epic S2, #4436): a Composio tool call ships the
// (already-normalized) arguments to the third-party provider — disclose
// the transfer before the round-trip. S4 will add an approval arm here.
let egress = crate::openhuman::security::egress::EgressDescriptor::composio(tool);
// Local-only enforcement (privacy epic S7, #4441): refuse the external
// tool call under LocalOnly BEFORE disclosing or sending it.
crate::openhuman::security::egress::enforce_egress(&egress)?;
crate::openhuman::security::egress::emit_external_transfer(egress);
// PR #1827 routes all execute-side argument normalization
// (including the bare-date → RFC 3339 fix #1802 brought to
// `normalize_calendar_query_args` on `main`) through the
// centralized `prepare_execute_arguments` helper. The helper
// covers the same calendar query case and is the shared entry
// point for `composio_execute`, per-action tools, and direct-
// mode dispatch.
let arguments = super::execute_prepare::prepare_execute_arguments(tool, arguments)
.map_err(anyhow::Error::msg)?;View on GitHub (pinned to 7491200858)
Solutions
- Fix the producer of the slug — an empty slug is a caller bug, not a Composio failure
- Validate and trim the slug where the tool call is parsed, and re-prompt or skip on blank
- Cross-check slug values against the tool list from list_tools so typos and empties are both caught early
Example fix
// before
let resp = client.execute_tool(action.as_str(), Some(args)).await?;
// after
let action = action.trim();
if action.is_empty() {
anyhow::bail!("tool call arrived with an empty action slug");
}
let resp = client.execute_tool(action, Some(args)).await?; Defensive patterns
Strategy: validation
Validate before calling
let tool = tool.trim();
if tool.is_empty() {
anyhow::bail!("tool slug is required for composio execution");
}
let resp = client.execute_tool(tool, arguments).await?; Type guard
fn is_non_empty_slug(s: &str) -> bool {
!s.trim().is_empty()
} Try / catch
match client.execute_tool(tool, arguments).await {
Ok(resp) => Ok(resp),
Err(err) if err.to_string().contains("tool slug must not be empty") => {
re_prompt_agent_for_action().await
}
Err(err) => Err(err),
} Prevention
- Validate slugs where LLM tool calls are parsed — blank names are model output bugs
- Cross-check requested slugs against list_tools output to catch blanks and typos in one pass
- Never default a missing slug to an empty string; make it a required field with a schema error
When it happens
Trigger: Calling execute_tool("", arguments) or with a whitespace-only slug — typically an agent/LLM tool invocation whose action name is missing while arguments are present.
Common situations: LLM emits a tool call with a blank function name; slug built by string concatenation where one part was empty; tool name read from a renamed/missing config or tool-definition key.
Related errors
- composio.execute_tool_once: tool slug must not be empty
- composio.execute_tool: tool slug must not be empty
- composio.authorize: toolkit must not be empty
- composio.delete_connection: connectionId must not be empty
- composio.create_trigger: slug must not be empty
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/19470b0d544289e6.
Report an issue: GitHub.