tinyhumansai/openhuman · error · anyhow::Error
composio.authorize: toolkit must not be empty
Error message
composio.authorize: toolkit must not be empty
What it means
ComposioClient::authorize rejects a toolkit name that is empty after trimming, before the POST /agent-integrations/composio/authorize request is built. It is a precondition guard: the backend would reject the call anyway, so the client fails fast with a precise message.
Source
Thrown at src/openhuman/integrations/composio/client.rs:90
.await
}
/// `POST /agent-integrations/composio/authorize` — begin an OAuth
/// handoff for `toolkit` and return the hosted `connectUrl` the user
/// must open in a browser.
///
/// `extra_params` is an optional JSON object whose key/value pairs are
/// merged into the request body. Some toolkits (e.g. `whatsapp`) require
/// additional fields (e.g. `waba_id`) that Composio will reject the
/// authorization without.
pub async fn authorize(
&self,
toolkit: &str,
extra_params: Option<serde_json::Value>,
) -> Result<ComposioAuthorizeResponse> {
let toolkit = toolkit.trim();
if toolkit.is_empty() {
anyhow::bail!("composio.authorize: toolkit must not be empty");
}
tracing::debug!(toolkit = %toolkit, has_extra_params = extra_params.is_some(), "[composio] authorize");
let mut body = serde_json::json!({ "toolkit": toolkit });
if let Some(extra) = extra_params {
const RESERVED: &[&str] = &["toolkit", "toolkit_version", "auth", "client_id"];
let extra_obj = extra.as_object().ok_or_else(|| {
anyhow::anyhow!("composio.authorize: extra_params must be a JSON object")
})?;
let obj = body.as_object_mut().ok_or_else(|| {
anyhow::anyhow!("composio.authorize: internal payload must be an object")
})?;
for (k, v) in extra_obj {
if RESERVED.contains(&k.as_str()) {
anyhow::bail!(
"composio.authorize: extra_params cannot override reserved key '{k}'"
);
}
obj.insert(k.clone(), v.clone());View on GitHub (pinned to 7491200858)
Solutions
- Make the toolkit selection mandatory in the calling UI/flow before authorize is reachable
- Trim and validate the toolkit id at the boundary (request parsing / RPC handler) with a descriptive error
- If toolkit ids come from a catalog list, validate against the listed ids to also catch typos
Example fix
// before
let resp = client.authorize(toolkit_from_form.as_str(), None).await?;
// after
let toolkit = toolkit_from_form.trim();
if toolkit.is_empty() {
return Err(anyhow::anyhow!("select a toolkit before authorizing"));
}
let resp = client.authorize(toolkit, None).await?; Defensive patterns
Strategy: validation
Validate before calling
let toolkit = toolkit.trim();
if toolkit.is_empty() {
return Err(anyhow::anyhow!("select a toolkit before authorizing"));
}
let resp = client.authorize(toolkit, extra_params).await?; Type guard
fn is_non_empty_toolkit(s: &str) -> bool {
!s.trim().is_empty()
} Prevention
- Make toolkit a required field in the connection-request schema with a descriptive error
- Populate toolkit pickers from the toolkits catalog so only valid ids can be submitted
- Trim user input at the RPC boundary so whitespace-only cannot reach authorize
When it happens
Trigger: Calling client.authorize("", extra_params) or with a toolkit of only whitespace — usually an unselected value from a UI dropdown or an unpopulated config field.
Common situations: Frontend submits the connection form before a toolkit was chosen; toolkit id read from a stale/renamed config key that no longer exists; data-entry path that trims user input to nothing.
Related errors
- composio.execute_tool: tool slug must not be empty
- composio.delete_connection: connectionId must not be empty
- composio.execute_tool: tool slug must not be empty
- composio.execute_tool_once: tool slug 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/5380d1470e996e27.
Report an issue: GitHub.