aaif-goose/goose · error
Failed to persist extension state: {}
Error message
Failed to persist extension state: {} What it means
Agent::remove_extension removes the extension from the running agent successfully, then persists the new enabled-extension list to the session; this error means that persistence step failed (wraps persist_extension_state errors — serialization failure, session not found, or storage I/O). Note the asymmetry: the extension IS removed in memory, but the session metadata on disk may still list it.
Source
Thrown at crates/goose/src/agents/agent.rs:1541
if extension_name.is_none() {
if let Some(final_output_tool) = self.final_output_tool.lock().await.as_ref() {
prefixed_tools.push(final_output_tool.tool());
}
}
prefixed_tools
}
pub async fn remove_extension(&self, name: &str, session_id: &str) -> Result<()> {
self.extension_manager.remove_extension(name).await?;
self.remove_frontend_extension(name).await;
// Persist extension state after successful removal
self.persist_extension_state(session_id)
.await
.map_err(|e| {
error!("Failed to persist extension state: {}", e);
anyhow!("Failed to persist extension state: {}", e)
})?;
Ok(())
}
pub async fn list_extensions(&self) -> Vec<String> {
let mut extensions = self
.extension_manager
.list_extensions()
.await
.expect("Failed to list extensions");
extensions.extend(
self.frontend_extension_configs()
.await
.into_iter()
.map(|config| config.name()),
);
extensionsView on GitHub (pinned to 3810898a74)
Solutions
- Verify the session_id exists and its storage is writable (check the sessions directory under the goose config dir)
- Retry the removal once storage is healthy — note the in-memory removal already succeeded, so a restart without persist will resurrect the extension
- If it keeps failing, manually clear the 'enabled_extensions.v0' entry in the session's extension_data
- Read the wrapped {e} to distinguish 'session not found' from serialization failure
Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm the session is readable/writable before removing:
if session_manager.get_session(session_id, false).await.is_err() {
anyhow::bail!("session {session_id} unavailable; refusing to remove extension");
} Type guard
fn persist_failed(e: &anyhow::Error) -> bool {
e.to_string().contains("Failed to persist extension state")
} Try / catch
if let Err(e) = agent.remove_extension(name, session_id).await {
if persist_failed(&e) {
// in-memory removal already happened; re-run persistence or accept
// that a restart may re-enable the extension
} else {
return Err(e);
}
} Prevention
- Verify session storage health before extension add/remove operations
- After this error, manually verify session extension_data before restarting
- Don't assume remove_extension failure means the extension is still loaded
When it happens
Trigger: persist_extension_state fails because session_manager.get_session(session_id) can't find/read the session, the session store is unwritable, or EnabledExtensionsState serialization fails (see the sibling 'Failed to serialize extension state' error).
Common situations: Session file deleted or moved while goose is running; permissions/disk issues on the sessions directory; session_id passed from a different/older session; serializer/version-skew issues on the extension list.
Related errors
- Extension state serialization failed: {}
- Request not found: {}
- Failed to serialize extension state: {}
- 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/46cbf276976f4213.
Report an issue: GitHub.