tinyhumansai/openhuman · error
learning_forget_facet: upsert failed: {e:#}
Error message
learning_forget_facet: upsert failed: {e:#} What it means
Thrown by learning_forget_facet when the facet was found and mutated in memory (user_state=Forgotten, state=Dropped) but FacetCache::upsert() failed. Consequence to understand: the forget did NOT persist — the facet remains active/pinned and will keep appearing in prompts until a successful retry.
Source
Thrown at src/openhuman/agent/learning/tools.rs:391
PermissionLevel::Write
}
async fn execute(&self, args: serde_json::Value) -> anyhow::Result<ToolResult> {
log::debug!("[tool][learning] forget_facet invoked");
let class_str = read_required_str(&args, "class")?;
let key_suffix = read_required_str(&args, "key")?;
let fk = full_key(&class_str, &key_suffix);
let cache = get_cache()?;
let facet_json = match cache
.get(&fk)
.map_err(|e| anyhow::anyhow!("learning_forget_facet: {e:#}"))?
{
Some(mut f) => {
f.user_state = UserState::Forgotten;
f.state = FacetState::Dropped;
cache
.upsert(&f)
.map_err(|e| anyhow::anyhow!("learning_forget_facet: upsert failed: {e:#}"))?;
facet_to_json(&f)
}
None => serde_json::Value::Null,
};
Ok(ToolResult::success(serde_json::to_string(&json!({
"facet": facet_json,
}))?))
}
}
/// Rebuild the facet cache (heavyweight stability cycle). Default-OFF.
pub struct LearningRebuildCacheTool;
#[async_trait]
impl Tool for LearningRebuildCacheTool {
fn name(&self) -> &str {
"learning_rebuild_cache"
}View on GitHub (pinned to a221052e0d)
Solutions
- Retry the forget once the lock clears and confirm the facet now shows user_state 'forgotten' via learning_get_facet
- Serialize forget/rebuild/reset calls — they all write the same table
- Check disk space / single-core-per-workspace if it recurs
Defensive patterns
Strategy: retry
Try / catch
if let Err(e) = tool_exec("learning_forget_facet", args).await {
if e.to_string().contains("upsert failed") {
tokio::time::sleep(Duration::from_millis(500)).await;
tool_exec("learning_forget_facet", args).await?; // retry
// then confirm: learning_get_facet -> user_state == forgotten
}
} Prevention
- Never assume a failed forget worked — an un-persisted forgotten facet keeps influencing prompts
- Verify with learning_get_facet (user_state 'forgotten', state 'dropped') after retrying
When it happens
Trigger: Forget racing learning_rebuild_cache or another writer holding the SQLite lock; disk full; read-only DB. The read succeeded moments earlier, so this is a write-time failure.
Common situations: User asks to 'stop remembering X' right as a scheduled reflection persist runs; the retry is then skipped because the tool reported failure and the caller assumes it worked.
Related errors
- learning_update_facet: upsert failed: {e:#}
- learning_forget_facet: {e:#}
- learning_update_facet: {e:#}
- {tool}: set_user_state failed: {e:#}
- {tool}: re-read failed: {e:#}
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/cbd4e4c95b27eef2.
Report an issue: GitHub.