{"record":{"id":"46cbf276976f4213","repo":"aaif-goose/goose","slug":"failed-to-persist-extension-state","errorCode":null,"errorMessage":"Failed to persist extension state: {}","messagePattern":"Failed to persist extension state: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose/src/agents/agent.rs","lineNumber":1541,"sourceCode":"        if extension_name.is_none() {\n            if let Some(final_output_tool) = self.final_output_tool.lock().await.as_ref() {\n                prefixed_tools.push(final_output_tool.tool());\n            }\n        }\n\n        prefixed_tools\n    }\n\n    pub async fn remove_extension(&self, name: &str, session_id: &str) -> Result<()> {\n        self.extension_manager.remove_extension(name).await?;\n        self.remove_frontend_extension(name).await;\n\n        // Persist extension state after successful removal\n        self.persist_extension_state(session_id)\n            .await\n            .map_err(|e| {\n                error!(\"Failed to persist extension state: {}\", e);\n                anyhow!(\"Failed to persist extension state: {}\", e)\n            })?;\n\n        Ok(())\n    }\n\n    pub async fn list_extensions(&self) -> Vec<String> {\n        let mut extensions = self\n            .extension_manager\n            .list_extensions()\n            .await\n            .expect(\"Failed to list extensions\");\n        extensions.extend(\n            self.frontend_extension_configs()\n                .await\n                .into_iter()\n                .map(|config| config.name()),\n        );\n        extensions","sourceCodeStart":1523,"sourceCodeEnd":1559,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose/src/agents/agent.rs#L1523-L1559","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Confirm the session is readable/writable before removing:\nif session_manager.get_session(session_id, false).await.is_err() {\n    anyhow::bail!(\"session {session_id} unavailable; refusing to remove extension\");\n}","typeGuard":"fn persist_failed(e: &anyhow::Error) -> bool {\n    e.to_string().contains(\"Failed to persist extension state\")\n}","tryCatchPattern":"if let Err(e) = agent.remove_extension(name, session_id).await {\n    if persist_failed(&e) {\n        // in-memory removal already happened; re-run persistence or accept\n        // that a restart may re-enable the extension\n    } else {\n        return Err(e);\n    }\n}","preventionTips":["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"],"tags":["rust","goose","extensions","session","persistence"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}