{"record":{"id":"5f46535155f6407a","repo":"aaif-goose/goose","slug":"planner-returned-no-agent-visible-text-to-classify","errorCode":null,"errorMessage":"Planner returned no agent-visible text to classify","messagePattern":"Planner returned no agent-visible text to classify","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/session/mod.rs","lineNumber":291,"sourceCode":"            &model_config,\n            \"Reply only with the classification label: \\\"plan\\\" or \\\"clarifying questions\\\"\",\n            &[message],\n            &[],\n        ),\n    )\n    .await?;\n\n    let predicted = result.as_concat_text();\n    if predicted.to_lowercase().contains(\"plan\") {\n        Ok(PlannerResponseType::Plan)\n    } else {\n        Ok(PlannerResponseType::ClarifyingQuestions)\n    }\n}\n\nfn planner_classification_text(response: &Message) -> Result<String> {\n    let text = response.agent_visible_content().as_concat_text();\n    anyhow::ensure!(\n        !text.trim().is_empty(),\n        \"Planner returned no agent-visible text to classify\"\n    );\n    Ok(text)\n}\n\nimpl CliSession {\n    #[allow(clippy::too_many_arguments)]\n    pub async fn new(\n        agent: Agent,\n        session_id: String,\n        debug: bool,\n        scheduled_job_id: Option<String>,\n        max_turns: Option<u32>,\n        edit_mode: Option<EditMode>,\n        retry_config: Option<RetryConfig>,\n        output_format: String,\n        stats: bool,","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/session/mod.rs#L273-L309","documentation":"In plan mode, goose sends the conversation to a planner model and classifies the reply as Plan or ClarifyingQuestions by scanning its agent-visible text (content the model sees, excluding hidden or tool-only payloads). planner_classification_text fails when that text is empty or whitespace-only, so classification cannot proceed.","triggerScenarios":"Invoking the plan flow (/plan or the planner path in session/mod.rs) when the planner model returns an empty completion, filtered content, or a response containing only non-agent-visible content.","commonSituations":"GOOSE_PLANNER_MODEL pointing at a model that returns empty bodies; provider outages returning empty content; reasoning-only responses with no text part.","solutions":["Retry the plan request — empty completions are usually transient","Validate GOOSE_PLANNER_MODEL and its provider credentials (goose configure)","Switch the planner to a known-good model (or unset the variable to use the default)","Run with --debug to inspect the raw planner response"],"exampleFix":"# before\nexport GOOSE_PLANNER_MODEL=provider/empty-reply-model\n# after\nunset GOOSE_PLANNER_MODEL   # fall back to the configured default model","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt in 0..3 {\n    match planner_classification_text(&response).await {\n        Ok(text) => break text,\n        Err(e) if attempt < 2 && e.to_string().contains(\"no agent-visible text\") => {\n            response = ask_planner(&messages).await?;\n        }\n        Err(e) => return Err(e),\n    }\n}","preventionTips":["Pin the planner to a model known to return text bodies","Treat empty planner completions as transient and retry once before failing","Enable debug logging during plan flows to see raw planner responses"],"tags":["planner","llm-response","classification","cli"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}