aaif-goose/goose · error
No user message
Error message
No user message
What it means
reply() takes the last message in self.messages as the user turn to send to the provider. When the message list is empty there is no last element, so it fails with 'No user message' before any provider call is made.
Source
Thrown at crates/goose-cli/src/session/mod.rs:1440
async fn process_agent_response(
&mut self,
interactive: bool,
cancel_token: CancellationToken,
) -> Result<()> {
let is_json_mode = self.output_format == "json";
let is_stream_json_mode = self.output_format == "stream-json";
let session_config = SessionConfig {
id: self.session_id.clone(),
schedule_id: self.scheduled_job_id.clone(),
max_turns: self.max_turns,
retry_config: self.retry_config.clone(),
};
let user_message = self
.messages
.last()
.ok_or_else(|| anyhow::anyhow!("No user message"))?;
let cancel_token_interrupt = cancel_token.clone();
let handle = tokio::spawn(async move {
if ctrl_c().await.is_ok() {
cancel_token_interrupt.cancel();
}
});
let _drop_handle = AbortOnDropHandle::new(handle);
let mut stream = self
.agent
.reply(
user_message.clone(),
session_config.clone(),
Some(cancel_token.clone()),
)
.await?;
View on GitHub (pinned to 3810898a74)
Solutions
- Push a user prompt into session.messages before invoking reply
- For goose run, supply the prompt via flags/args so the session starts non-empty
- If building on the API, assert !messages.is_empty() as a precondition
Example fix
// before let reply = session.reply(&provider, cancel_token).await?; // after session.add_message(Message::user().with_text(prompt.clone())); let reply = session.reply(&provider, cancel_token).await?;
Defensive patterns
Strategy: validation
Validate before calling
assert!(
!session.messages.is_empty(),
"reply() requires at least one message; add the user prompt first"
); Prevention
- Always add the user message before calling reply
- For headless runs, pass the prompt via flags or recipe so the session starts non-empty
- Treat an empty message list as a caller bug, not a runtime condition
When it happens
Trigger: Headless or recipe paths (goose run, resumed sessions, scheduled jobs, custom harnesses) that call reply before any user message was pushed into the session.
Common situations: Recipes without an initial prompt; resumed sessions whose persisted history is empty; integrations constructing a CliSession and calling reply directly without adding a message.
Related errors
- No session found to resume
- No session found with name '{}'
- Could not extract session ID from path: {:?}
- Invalid identifier
- Cannot use --session-id without --resume
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/58532a1ea647ed2d.
Report an issue: GitHub.