tinyhumansai/openhuman · error

channel is required

Error message

channel is required

What it means

Thrown by create_channel_link_token when the channel argument is empty after trimming whitespace and stripping slashes. The channel becomes a URL path segment (auth/channels/{channel}/link-token) naming which integration the short-lived link token is for; an empty segment has no referent. Caller-input validation only — nothing is sent.

Source

Thrown at src/api/rest.rs:555

            .to_string();
        anyhow::ensure!(!jwt.is_empty(), "consume login token response missing jwt");
        Ok(jwt)
    }

    /// Validates that the provided session token is still active and accepted.
    pub async fn validate_session_token(&self, bearer_jwt: &str) -> Result<()> {
        let _ = self.fetch_current_user(bearer_jwt).await?;
        Ok(())
    }

    /// Creates a short-lived link token for connecting a specific communication channel.
    pub async fn create_channel_link_token(
        &self,
        channel: &str,
        bearer_jwt: &str,
    ) -> Result<Value> {
        let channel = channel.trim().trim_matches('/');
        anyhow::ensure!(!channel.is_empty(), "channel is required");
        let encoded_channel = urlencoding::encode(channel);

        self.authed_json(
            bearer_jwt,
            Method::POST,
            &format!("auth/channels/{encoded_channel}/link-token"),
            None,
        )
        .await
    }

    /// Generic authenticated JSON request helper for backend API routes.
    pub async fn authed_json(
        &self,
        bearer_jwt: &str,
        method: Method,
        path: &str,
        body: Option<Value>,

View on GitHub (pinned to a221052e0d)

Solutions

  1. Pass the concrete channel/provider identifier from the integration record
  2. Validate the channel field where the record is created so blank integrations cannot enter the store
  3. Guard at the call site with the same trim+slash normalization the method applies

Example fix

// before
let v = client.create_channel_link_token(&ch, &jwt).await?; // ch = ""

// after
let ch = ch.trim().trim_matches('/');
anyhow::ensure!(!ch.is_empty(), "channel is required for link-token creation");
let v = client.create_channel_link_token(ch, &jwt).await?;
Defensive patterns

Strategy: validation

Validate before calling

let channel = channel.trim().trim_matches('/');
anyhow::ensure!(!channel.is_empty(), "channel is required for link-token creation");
let v = client.create_channel_link_token(channel, &jwt).await?;

Type guard

fn normalize_channel(raw: &str) -> Option<String> {
    let c = raw.trim().trim_matches('/');
    (!c.is_empty()).then(|| c.to_string())
}

Prevention

When it happens

Trigger: Calling create_channel_link_token("", ...) or create_channel_link_token("/", ...) — e.g. the channel id was taken from a channel-connection record whose provider field was blank.

Common situations: A channel integration row created before a schema change left the provider field empty, or the pairing UI passed its unselected state straight through.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/779bb276bb6d3cdd. Report an issue: GitHub.