aaif-goose/goose · error
Extension state serialization failed: {}
Error message
Extension state serialization failed: {} What it means
Agent::save_extension_state serializes the agent's current extension list as EnabledExtensionsState and writes it into the session's extension_data under key 'enabled_extensions.v0'. This error means serde failed to serialize the Vec<ExtensionConfig> itself (to_extension_data -> to_value), before any storage write happened.
Source
Thrown at crates/goose/src/agents/agent.rs:1260
(
request_id,
Ok(self.with_post_tool_hook(result, &tool_call, session)),
)
}
/// Save current extension state to session metadata
/// Should be called after any extension add/remove operation
pub async fn save_extension_state(&self, session: &SessionConfig) -> Result<()> {
let extensions_state =
EnabledExtensionsState::new(self.extension_configs_for_persistence().await);
let session_manager = self.config.session_manager.clone();
let mut session_data = session_manager.get_session(&session.id, false).await?;
if let Err(e) = extensions_state.to_extension_data(&mut session_data.extension_data) {
warn!("Failed to serialize extension state: {}", e);
return Err(anyhow!("Extension state serialization failed: {}", e));
}
session_manager
.update(&session.id)
.extension_data(session_data.extension_data)
.apply()
.await?;
Ok(())
}
/// Save current extension state to session by session_id
pub async fn persist_extension_state(&self, session_id: &str) -> Result<()> {
let extensions_state =
EnabledExtensionsState::new(self.extension_configs_for_persistence().await);
let session_manager = self.config.session_manager.clone();
let session = session_manager.get_session(session_id, false).await?;View on GitHub (pinned to 3810898a74)
Solutions
- Identify the recently added/changed extension — serialize each ExtensionConfig individually to find the offender
- Update goose so the in-memory ExtensionConfig enum and serializer agree
- Remove the offending extension and retry the save
- If the session's stored state is corrupt, start a fresh session rather than fighting the old one
Defensive patterns
Strategy: try-catch
Validate before calling
// probe-serialize before saving so the failing extension is identifiable:
for ext in agent.extension_configs_for_persistence().await {
if serde_json::to_value(&ext).is_err() {
tracing::error!("unserializable extension config: {:?}", ext);
}
} Type guard
fn extension_state_serialization_failed(e: &anyhow::Error) -> bool {
e.to_string().contains("Extension state serialization failed")
} Try / catch
if let Err(e) = agent.save_extension_state(&session).await {
if extension_state_serialization_failed(&e) {
// keep the session running; flag the offending extension for removal
tracing::error!("extension state not saved: {e}");
} else {
return Err(e);
}
} Prevention
- Keep goose and extensions version-aligned
- Test add/remove extension flows after upgrades
- Remove extensions that fail serialization instead of retrying blindly
When it happens
Trigger: An ExtensionConfig variant currently loaded in the agent cannot be represented as JSON — e.g. a serde tag/shape mismatch after a goose upgrade changed the ExtensionConfig enum, or an extension config constructed programmatically with non-serializable content.
Common situations: Upgrading goose while sessions hold extension configs of the old shape and then calling save_extension_state on a code path that still uses old configs; custom-built extensions with unserializable fields; config migrations that leave a legacy variant in memory.
Related errors
- Failed to serialize extension state: {}
- Failed to persist extension state: {}
- Request not found: {}
- Failed to fetch updated session: {}
- Session has no conversation after history modification
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/a8bb7e9711b468ac.
Report an issue: GitHub.