{"record":{"id":"8ae967f02bb9392b","repo":"tinyhumansai/openhuman","slug":"learning-update-facet-upsert-failed-e","errorCode":null,"errorMessage":"learning_update_facet: upsert failed: {e:#}","messagePattern":"learning_update_facet: upsert failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/agent/learning/tools.rs","lineNumber":254,"sourceCode":"        PermissionLevel::Write\n    }\n\n    async fn execute(&self, args: serde_json::Value) -> anyhow::Result<ToolResult> {\n        log::debug!(\"[tool][learning] update_facet invoked\");\n        let class_str = read_required_str(&args, \"class\")?;\n        let key_suffix = read_required_str(&args, \"key\")?;\n        let value = read_required_str(&args, \"value\")?;\n        let fk = full_key(&class_str, &key_suffix);\n        let cache = get_cache()?;\n        let mut facet = cache\n            .get(&fk)\n            .map_err(|e| anyhow::anyhow!(\"learning_update_facet: {e:#}\"))?\n            .ok_or_else(|| anyhow::anyhow!(\"learning_update_facet: facet not found: {fk}\"))?;\n        facet.value = value;\n        facet.user_state = UserState::Pinned;\n        cache\n            .upsert(&facet)\n            .map_err(|e| anyhow::anyhow!(\"learning_update_facet: upsert failed: {e:#}\"))?;\n        Ok(ToolResult::success(serde_json::to_string(&json!({\n            \"facet\": facet_to_json(&facet),\n        }))?))\n    }\n}\n\n/// Set/clear a facet's pin via `set_user_state`. Shared by pin/unpin.\nasync fn set_pin(\n    args: serde_json::Value,\n    tool: &str,\n    state: UserState,\n) -> anyhow::Result<ToolResult> {\n    let class_str = read_required_str(&args, \"class\")?;\n    let key_suffix = read_required_str(&args, \"key\")?;\n    let fk = full_key(&class_str, &key_suffix);\n    let cache = get_cache()?;\n    let updated = cache\n        .set_user_state(&fk, state)","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/src/openhuman/agent/learning/tools.rs#L236-L272","documentation":"Thrown by learning_update_facet when the facet was read and mutated in memory but FacetCache::upsert() (ProfileStore::upsert_full) failed to persist it. It is the write-path twin of the get error: the value change and the UserState::Pinned transition were NOT saved. Causes are SQLite write failures — busy database, disk full, constraint/I/O errors.","triggerScenarios":"learning_update_facet executes its UPDATE while a stability rebuild or learning_reset_cache is writing the same table; disk full; DB opened read-only or corrupted. The tool had already fetched the facet successfully, so the read path was healthy at that moment.","commonSituations":"Update racing learning_rebuild_cache or learning_forget_facet on the same key; low-disk laptops; a second core instance pointed at the same workspace_dir.","solutions":["Retry the update once the concurrent writer (rebuild/reset/reflection) finishes","Verify the facet's persisted state afterwards with learning_get_facet — if the old value is still there the upsert truly did not land","Check disk space and workspace_dir DB permissions","Ensure only one core process uses the workspace (OPENHUMAN_CORE_REUSE_EXISTING debugging leftovers are a classic double-open)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let res = tool_exec(\"learning_update_facet\", args).await;\nif let Err(e) = &res {\n    if e.to_string().contains(\"upsert failed\") && e.to_string().contains(\"locked\") {\n        tokio::time::sleep(Duration::from_millis(500)).await;\n        return tool_exec(\"learning_update_facet\", args).await; // idempotent value write\n    }\n}\nres","preventionTips":["After any reported upsert failure, verify with learning_get_facet whether the value landed before re-sending","Do not interleave learning_rebuild_cache and facet updates in the same turn","Watch disk space — full disks turn transient lock errors into persistent I/O errors"],"tags":["rust","sqlite","learning","agent-tools","write-path"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}