aaif-goose/goose · warning
Session has no messages
Error message
Session has no messages
What it means
Raised only for `--format markdown`: markdown export renders the conversation transcript, so session.conversation must be Some. Sessions that were created but never recorded messages (or migrated/imported files lacking the conversation field) have conversation = None and cannot be rendered as markdown. JSON and YAML export work because they serialize the whole session object.
Source
Thrown at crates/goose-cli/src/commands/session.rs:251
let session_manager = SessionManager::instance();
let session = match session_manager.get_session(&session_id, true).await {
Ok(session) => session,
Err(e) => {
return Err(anyhow::anyhow!(
"Session '{}' not found or failed to read: {}",
session_id,
e
));
}
};
let output = match format.as_str() {
"json" => serde_json::to_string_pretty(&session)?,
"yaml" => serde_yaml::to_string(&session)?,
"markdown" => {
let conversation = session
.conversation
.ok_or_else(|| anyhow::anyhow!("Session has no messages"))?;
export_session_to_markdown(conversation.user_visible_messages(), &session.name)
}
_ => return Err(anyhow::anyhow!("Unsupported format: {}", format)),
};
#[cfg(feature = "nostr")]
if nostr {
if format != "json" {
return Err(anyhow::anyhow!(
"Nostr session sharing only supports --format json"
));
}
if output_path.is_some() {
return Err(anyhow::anyhow!(
"Nostr session sharing cannot be combined with --output"
));
}
View on GitHub (pinned to 3810898a74)
Solutions
- Export the same session as --format json or yaml (they do not require messages)
- Pick a session that actually has messages (`goose session list` shows activity)
- Send at least one message in the session before markdown export
Example fix
# before goose session export <empty-session-id> --format markdown # after goose session export <empty-session-id> --format json goose session export <session-with-messages> --format markdown
Defensive patterns
Strategy: validation
Validate before calling
let session = session_manager.get_session(&id, true).await?;
let format = if session_has_messages(&session) { "markdown" } else { "json" }; Type guard
fn session_has_messages(s: &Session) -> bool {
s.conversation
.as_ref()
.is_some_and(|c| !c.user_visible_messages().is_empty())
} Try / catch
match handle_session_export(id, None, "markdown".into(), false, vec![]).await {
Err(e) if e.to_string() == "Session has no messages" => {
handle_session_export(id, None, "json".into(), false, vec![]).await // fall back to json
}
other => other,
} Prevention
- Default to json for automation; markdown only for sessions you know have traffic
- Check a session has activity in `goose session list` before markdown export
When it happens
Trigger: `goose session export <id> --format markdown` on a session with zero messages; exporting a just-created session before any turn completes; importing a transcript that goose stored without a conversation payload.
Common situations: Testing export on a throwaway empty session; exporting immediately after `goose session start` before chatting; sessions created by headless/automation runs that errored out before writing messages.
Related errors
- No sessions found
- No sessions found.
- Session '{}' not found or failed to read: {}
- Unsupported format: {}
- Nostr session sharing only supports --format json
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/dce48af5dea20d8c.
Report an issue: GitHub.