tinyhumansai/openhuman · error · anyhow::Error
composio.authorize: {AUTHORIZE_OAUTH_SCOPES_FIELD} must be a
Error message
composio.authorize: {AUTHORIZE_OAUTH_SCOPES_FIELD} must be a string or array What it means
The shape-level guard of merge_required_oauth_scopes: the oauth_scopes field must be a JSON string (comma/whitespace separated, which the client splits) or an array of strings. Any other JSON type — object, number, boolean — bails client-side before the authorize request is sent.
Source
Thrown at src/openhuman/integrations/composio/client.rs:640
.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 {
if !scopes.iter().any(|existing| existing == scope) {
scopes.push((*scope).to_string());
}
}
*value = json!(scopes);
Ok(())
}
/// Backend-mode [`ComposioClient`] constructor. **Internal to the
/// composio module** — external callers should use
/// [`create_composio_client`] (factory) or
/// [`crate::openhuman::agent::harness::subagent_runner::user_is_signed_in_to_composio`]View on GitHub (pinned to 7491200858)
Solutions
- Fix the producer to emit either a comma/space-separated string or an array of scope strings
- If you have an object-style scope map, flatten it to an array of granted scope names before calling
- Validate the oauth_scopes shape at config load time (null/string/array-of-strings only)
Example fix
// before
let extra = json!({ "oauth_scopes": {"repo": true} });
client.authorize("github", Some(extra)).await?;
// after — flatten a scope map into the accepted array form
let scopes: Vec<String> = scope_map
.iter()
.filter(|(_, v)| v.as_bool().unwrap_or(false))
.map(|(k, _)| k.clone())
.collect();
let extra = json!({ "oauth_scopes": scopes });
client.authorize("github", Some(extra)).await?; Defensive patterns
Strategy: type-guard
Validate before calling
// Normalize any scope representation into the accepted string|array-of-strings shape
fn normalize_oauth_scopes(v: &serde_json::Value) -> serde_json::Value {
match v {
serde_json::Value::Null => serde_json::Value::Array(vec![]),
serde_json::Value::String(_) => v.clone(),
serde_json::Value::Array(_) => v.clone(),
serde_json::Value::Object(map) => serde_json::Value::Array(
map.iter()
.filter(|(_, v)| v.as_bool().unwrap_or(false))
.map(|(k, _)| serde_json::json!(k))
.collect(),
),
_ => serde_json::Value::Array(vec![]), // numbers/bools carry no scopes
}
} Type guard
fn oauth_scopes_shape_ok(v: &serde_json::Value) -> bool {
matches!(v, serde_json::Value::Null | serde_json::Value::String(_))
|| v.as_array().is_some_and(|a| a.iter().all(|i| i.is_string()))
} Prevention
- Constrain the oauth_scopes config field to string or array-of-strings at schema level
- Flatten object-style scope maps ({"read": true}) into arrays of names before forwarding
- Add a unit test pinning the accepted shapes so accidental schema loosening fails in CI
When it happens
Trigger: Calling authorize with oauth_scopes set to a non-string, non-array value, e.g. {"oauth_scopes": 3}, {"oauth_scopes": true}, or {"oauth_scopes": {"read": true}}.
Common situations: Config schema loosened so any JSON is accepted for the field; a count or flag accidentally stored under the scopes key; object-style scope maps ("read": true) forwarded where a list is expected.
Related errors
- composio.authorize: {AUTHORIZE_OAUTH_SCOPES_FIELD} entries m
- 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/060122b0a30c71e3.
Report an issue: GitHub.