tinyhumansai/openhuman · error · anyhow::Error

composio.create_trigger: slug must not be empty

Error message

composio.create_trigger: slug must not be empty

What it means

ComposioClient::create_trigger rejects a trigger slug that is empty after trimming, before POST /agent-integrations/composio/triggers is built. The slug identifies the trigger type; blank input is a caller bug the client refuses to forward.

Source

Thrown at src/openhuman/integrations/composio/client.rs:362

        let path = match connection_id.map(str::trim).filter(|id| !id.is_empty()) {
            Some(id) => format!("/agent-integrations/composio/github/repos?connectionId={id}"),
            None => "/agent-integrations/composio/github/repos".to_string(),
        };
        tracing::debug!(path = %path, "[composio] list_github_repos");
        self.inner.get::<ComposioGithubReposResponse>(&path).await
    }

    /// `POST /agent-integrations/composio/triggers` — create a trigger
    /// instance for the authenticated user.
    pub async fn create_trigger(
        &self,
        slug: &str,
        connection_id: Option<&str>,
        trigger_config: Option<serde_json::Value>,
    ) -> Result<ComposioCreateTriggerResponse> {
        let slug = slug.trim();
        if slug.is_empty() {
            anyhow::bail!("composio.create_trigger: slug must not be empty");
        }
        let mut body = json!({ "slug": slug });
        if let Some(connection_id) = connection_id.map(str::trim).filter(|id| !id.is_empty()) {
            body["connectionId"] = json!(connection_id);
        }
        if let Some(config) = trigger_config {
            body["triggerConfig"] = config;
        }
        tracing::debug!(slug = %slug, "[composio] create_trigger");
        self.inner
            .post::<ComposioCreateTriggerResponse>("/agent-integrations/composio/triggers", &body)
            .await
    }

    // ── Trigger management (PR #671) ────────────────────────────────

    /// `GET /agent-integrations/composio/triggers/available` — catalog of
    /// triggers the user could enable for a toolkit. For GitHub the

View on GitHub (pinned to 7491200858)

Solutions

  1. Require trigger template selection before the create action is enabled
  2. Validate slug non-empty (and ideally against list_available_triggers output) at the RPC/config boundary
  3. Log the originating flow/automation when this fires to find which producer omits the slug

Example fix

// before
client.create_trigger(&node.slug, conn_id, cfg).await?;

// after
let slug = node.slug.trim();
if slug.is_empty() {
    anyhow::bail!("trigger node {} has no slug; fix the automation definition", node.id);
}
client.create_trigger(slug, conn_id, cfg).await?;
Defensive patterns

Strategy: validation

Validate before calling

let slug = slug.trim();
if slug.is_empty() {
    anyhow::bail!("trigger slug is required to create a trigger");
}
client.create_trigger(slug, connection_id, trigger_config).await?;

Type guard

fn is_non_empty_slug(s: &str) -> bool {
    !s.trim().is_empty()
}

Prevention

When it happens

Trigger: Calling create_trigger("", connection_id, trigger_config) or with a whitespace-only slug — usually a UI flow where the trigger template was not yet selected, or an automation config whose trigger key is missing.

Common situations: Trigger-creation form submitted with no template chosen; trigger slug read from a renamed config key; flows/automations engine instantiating a trigger from an incompletely-defined node.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/38e14542d36ccc22. Report an issue: GitHub.