aaif-goose/goose · error

'activities' is not an array'

Error message

'activities' is not an array'

What it means

Thrown during recipe response parsing when the "activities" key exists but its value is not a JSON array (as_array() fails) — for example an object or a plain string. Activities must be a list of strings for the recipe builder.

Source

Thrown at crates/goose/src/agents/agent.rs:3854

            .and_then(|caps| caps.get(1).map(|m| m.as_str()))
            .unwrap_or(&content)
            .trim()
            .to_string();

        let (instructions, activities) =
            if let Ok(json_content) = serde_json::from_str::<Value>(&clean_content) {
                let instructions = json_content
                    .get("instructions")
                    .ok_or_else(|| anyhow!("Missing 'instructions' in json response"))?
                    .as_str()
                    .ok_or_else(|| anyhow!("instructions' is not a string"))?
                    .to_string();

                let activities = json_content
                    .get("activities")
                    .ok_or_else(|| anyhow!("Missing 'activities' in json response"))?
                    .as_array()
                    .ok_or_else(|| anyhow!("'activities' is not an array'"))?
                    .iter()
                    .map(|act| {
                        act.as_str()
                            .map(|s| s.to_string())
                            .ok_or(anyhow!("'activities' array element is not a string"))
                    })
                    .collect::<Result<_, _>>()?;

                (instructions, activities)
            } else {
                tracing::warn!("Failed to parse JSON, falling back to string parsing");
                // If we can't get valid JSON, try string parsing
                // Use split_once to get the content after "Instructions:".
                let after_instructions = content
                    .split_once("instructions:")
                    .map(|(_, rest)| rest)
                    .unwrap_or(&content);

View on GitHub (pinned to 3810898a74)

Solutions

  1. Retry the generation
  2. Use a stronger or officially supported model
  3. Shorten the conversation being converted to reduce format drift
  4. Write the recipe YAML by hand
Defensive patterns

Strategy: retry

Validate before calling

// Rust — verify activities is an array before accepting the response
let ok = json.get("activities").and_then(|a| a.as_array()).is_some();
if !ok { /* regenerate */ }

Try / catch

// Rust — retry on shape errors, surface everything else
match generate_recipe(&agent, &conversation).await {
    Ok(r) => Ok(r),
    Err(e) if e.to_string().contains("is not an array") => retry_or_fallback(e),
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Model returns {"activities": "1. do x 2. do y"} or {"activities": {"1": "..."}} instead of a list during recipe generation.

Common situations: Models formatting activities as prose or numbered maps; schema drift on smaller/local models; output truncation producing malformed tails.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/b50eece139b03b36. Report an issue: GitHub.