aaif-goose/goose · error
Missing 'instructions' in json response
Error message
Missing 'instructions' in json response
What it means
Thrown while parsing the model's response during LLM recipe generation: the response WAS valid JSON (a fenced ```json block or raw object), but the object has no "instructions" key. Note goose only throws this when JSON parsing succeeded — non-JSON responses fall back to plain-text parsing instead, so this specifically means schema-conformant JSON with a missing field.
Source
Thrown at crates/goose/src/agents/agent.rs:3845
tracing::debug!(
"Provider returned content with {} characters",
content.len()
);
// the response may be contained in ```json ```, strip that before parsing json
let re = Regex::new(r"(?s)```[^\n]*\n(.*?)\n```").unwrap();
let clean_content = re
.captures(&content)
.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)View on GitHub (pinned to 3810898a74)
Solutions
- Retry the recipe generation — output-shape errors from LLMs are often nondeterministic
- Use a stronger / officially recommended model for recipe generation
- Shorten or clean the conversation being converted (very long inputs degrade schema adherence)
- As a workaround, author the recipe YAML by hand and load it with Recipe::from_file_path
Example fix
// before — model returns:
{ "activities": ["step 1"] } // Err: Missing 'instructions' in json response
// after — model returns:
{ "instructions": "Do X", "activities": ["step 1"] } Defensive patterns
Strategy: retry
Validate before calling
// Rust — validate the model's JSON shape before letting goose parse it
fn recipe_json_valid(v: &serde_json::Value) -> bool {
v.get("instructions").and_then(|i| i.as_str()).is_some()
&& v.get("activities")
.and_then(|a| a.as_array())
.is_some_and(|a| a.iter().all(|e| e.as_str().is_some()))
} Try / catch
// Rust — retry generation on schema errors; LLM output is nondeterministic
for attempt in 1..=3 {
match generate_recipe(&agent, &conversation).await {
Ok(r) => return Ok(r),
Err(e) if e.to_string().contains("json response") && attempt < 3 => continue,
Err(e) => return Err(e),
}
} Prevention
- Use a strong, instruction-following model for recipe generation
- Keep the source conversation focused — long inputs degrade JSON adherence
- Treat any single generation failure as retryable before investigating
When it happens
Trigger: Calling recipe generation with a model that returns JSON lacking "instructions" — e.g. it emits only {"activities": [...]} or uses a different key like "steps" or "system_prompt".
Common situations: Weaker models ignoring the output schema; prompt variations drifting from goose's recipe prompt; models paraphrasing key names; unusually long conversations causing the model to truncate its JSON.
Related errors
- instructions' is not a string
- Missing 'activities' in json response
- 'activities' is not an array'
- 'activities' array element is not a string
- Invalid deeplink or recipe format
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/ebd01ef9785476fc.
Report an issue: GitHub.