tinyhumansai/openhuman · error
learning_rebuild_cache: rebuild failed: {e:#}
Error message
learning_rebuild_cache: rebuild failed: {e:#} What it means
Thrown by learning_rebuild_cache when StabilityDetector::rebuild(now) fails. rebuild() recomputes facet stability from the accumulated evidence/candidate buffer and rewrites the user_profile table (adding, evicting, and keeping rows, respecting class budgets and pin protection) — a multi-row write cycle, so any store error mid-cycle aborts the whole rebuild. It is the heavyweight stability cycle, default-OFF alongside the other mutators.
Source
Thrown at src/openhuman/agent/learning/tools.rs:435
fn parameters_schema(&self) -> serde_json::Value {
json!({ "type": "object", "properties": {} })
}
fn permission_level(&self) -> PermissionLevel {
PermissionLevel::Execute
}
async fn execute(&self, _args: serde_json::Value) -> anyhow::Result<ToolResult> {
log::debug!("[tool][learning] rebuild_cache invoked");
let cache = get_cache()?;
let detector = StabilityDetector::new(cache);
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs_f64())
.unwrap_or(0.0);
let outcome = detector
.rebuild(now)
.map_err(|e| anyhow::anyhow!("learning_rebuild_cache: rebuild failed: {e:#}"))?;
Ok(ToolResult::success(serde_json::to_string(&json!({
"added": outcome.added,
"evicted": outcome.evicted,
"kept": outcome.kept,
"total_size": outcome.total_size,
}))?))
}
}
/// Reset the facet cache (delete all auto facets, keep pinned). Default-OFF.
pub struct LearningResetCacheTool;
#[async_trait]
impl Tool for LearningResetCacheTool {
fn name(&self) -> &str {
"learning_reset_cache"
}
View on GitHub (pinned to a221052e0d)
Solutions
- Ensure no other learning mutator is in flight, then retry the rebuild — it is designed as a full recompute, so a partial outcome is safe to redo
- Check learning_cache_stats afterwards to see the resulting row counts
- Free disk space / verify the workspace DB if the error chain shows I/O rather than lock errors
- If it fails deterministically, capture the {e:#} chain — a deserialization error on a specific row points at data corruption needing a reset_cache
Defensive patterns
Strategy: try-catch
Validate before calling
// Rebuild is a full recompute — safe to re-run, but check store health first:
tool_exec("learning_cache_stats", json!({})).await?; // errors => defer the rebuild Try / catch
match tool_exec("learning_rebuild_cache", json!({})).await {
Ok(out) => log::info!("rebuild added/evicted/kept: {out}"),
Err(e) => {
log::warn!("rebuild failed: {e:#}");
// leave cache as-is; it is still the last consistent snapshot — retry later when idle
}
} Prevention
- Run rebuilds when no other learning mutator or reflection persist is active
- A failed rebuild leaves the previous cache intact by design — do not 'fix' it with reset_cache unless rows are corrupted
- Budget for it: it rewrites the whole user_profile table
When it happens
Trigger: Invoking learning_rebuild_cache while pin/update/forget/reset tools or reflection persistence write the same table (lock contention aborts the transaction); disk full partway through the rewrite; corrupted evidence/facet rows tripping deserialization inside the detector.
Common situations: Agent-triggered rebuild overlapping a scheduled stability cycle; rebuild on a nearly-full disk leaving the cache partially rewritten; concurrent UI learning RPC calls.
Related errors
- learning_update_facet: {e:#}
- learning_update_facet: upsert failed: {e:#}
- {tool}: set_user_state failed: {e:#}
- {tool}: re-read failed: {e:#}
- learning_forget_facet: {e:#}
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/6c9efbb26ada74dd.
Report an issue: GitHub.