tinyhumansai/openhuman · error · anyhow::Error
composio.authorize: {AUTHORIZE_OAUTH_SCOPES_FIELD} entries m
Error message
composio.authorize: {AUTHORIZE_OAUTH_SCOPES_FIELD} entries must be strings What it means
merge_required_oauth_scopes normalizes the oauth_scopes field (AUTHORIZE_OAUTH_SCOPES_FIELD) of the authorize body before the request. When the field is an array but any element is not a JSON string (number, object, bool, null), it bails with this message client-side — the request never reaches Composio.
Source
Thrown at src/openhuman/integrations/composio/client.rs:628
}
}
Ok(())
}
fn append_missing_oauth_scopes(value: &mut Value, required: &[&str]) -> anyhow::Result<()> {
let mut scopes = match value {
Value::Null => Vec::new(),
Value::String(raw) => raw
.split(|ch: char| ch == ',' || ch.is_whitespace())
.map(str::trim)
.filter(|s| !s.is_empty())
.map(ToString::to_string)
.collect(),
Value::Array(items) => {
let mut out = Vec::with_capacity(items.len() + required.len());
for item in items {
let Some(scope) = item.as_str() else {
anyhow::bail!(
"composio.authorize: {AUTHORIZE_OAUTH_SCOPES_FIELD} entries must be strings"
);
};
let scope = scope.trim();
if !scope.is_empty() {
out.push(scope.to_string());
}
}
out
}
_ => {
anyhow::bail!(
"composio.authorize: {AUTHORIZE_OAUTH_SCOPES_FIELD} must be a string or array"
);
}
};
for scope in required {View on GitHub (pinned to 7491200858)
Solutions
- Coerce every scope element to a string (and drop empties) before calling authorize
- Prefer passing oauth_scopes as a single comma- or space-separated string — the client splits and trims it itself
- Validate the scopes shape where the config is loaded, so bad data fails with file/field context
Example fix
// before
let extra = json!({ "oauth_scopes": ["repo", 42] });
client.authorize("github", Some(extra)).await?;
// after — sanitize to strings before the call
let scopes: Vec<String> = raw_scopes
.iter()
.filter_map(|v| v.as_str().map(str::trim))
.filter(|s| !s.is_empty())
.map(ToString::to_string)
.collect();
let extra = json!({ "oauth_scopes": scopes });
client.authorize("github", Some(extra)).await?; Defensive patterns
Strategy: type-guard
Validate before calling
fn sanitize_scopes(value: &serde_json::Value) -> Vec<String> {
value
.as_array()
.map(|items| {
items
.iter()
.filter_map(|v| v.as_str().map(str::trim))
.filter(|s| !s.is_empty())
.map(ToString::to_string)
.collect()
})
.unwrap_or_default()
} Type guard
fn scopes_entries_are_strings(value: &serde_json::Value) -> bool {
value.as_array().is_some_and(|items| {
items.iter().all(|v| v.is_string() || v.is_null())
})
} Prevention
- Pass oauth_scopes as one comma/space-separated string — the client splits it and this whole class vanishes
- Validate scope arrays where config is deserialized, failing with the offending index
- Never build scope arrays from untyped template output without a stringify pass
When it happens
Trigger: Calling authorize with extra_params (or config data) where oauth_scopes is an array containing a non-string, e.g. ["repo", 42] or ["repo", {"scope":"issues"}].
Common situations: Scopes assembled by templating/serialization that produced numbers or nested objects; provider config copied from YAML where a scope entry parsed as a non-string; LLM-generated scope arrays with mixed types.
Related errors
- composio.authorize: {AUTHORIZE_OAUTH_SCOPES_FIELD} must be a
- composio.authorize: toolkit must not be empty
- composio.authorize: extra_params cannot override reserved ke
- composio direct authorize: toolkit must not be empty
- Composio connect failed on v3 ({v3_err}) and v2 fallback ({v
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/2b441cbcc318d4c4.
Report an issue: GitHub.