tinyhumansai/openhuman · error
{tool}: re-read failed: {e:#}
Error message
{tool}: re-read failed: {e:#} What it means
Thrown by set_pin when the pin/unpin UPDATE succeeded but the immediate re-read (FacetCache::get) of the same key failed. A rare storage failure between two statements in one tool call: the pin IS persisted, only the confirmation read failed. Same causes as the other store errors — lock transition, I/O error, DB closing underneath.
Source
Thrown at src/openhuman/agent/learning/tools.rs:279
/// Set/clear a facet's pin via `set_user_state`. Shared by pin/unpin.
async fn set_pin(
args: serde_json::Value,
tool: &str,
state: UserState,
) -> anyhow::Result<ToolResult> {
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 updated = cache
.set_user_state(&fk, state)
.map_err(|e| anyhow::anyhow!("{tool}: set_user_state failed: {e:#}"))?;
if !updated {
return Err(anyhow::anyhow!("{tool}: facet not found: {fk}"));
}
let facet = cache
.get(&fk)
.map_err(|e| anyhow::anyhow!("{tool}: re-read failed: {e:#}"))?;
Ok(ToolResult::success(serde_json::to_string(&json!({
"facet": facet.as_ref().map(facet_to_json),
}))?))
}
/// Pin a facet. Default-OFF.
pub struct LearningPinFacetTool;
#[async_trait]
impl Tool for LearningPinFacetTool {
fn name(&self) -> &str {
"learning_pin_facet"
}
fn description(&self) -> &str {
"Pin a learned facet (`class` + `key`) so it stays active regardless of \
the stability detector."
}View on GitHub (pinned to a221052e0d)
Solutions
- Treat the pin as probably applied — verify with learning_get_facet instead of blindly re-pinning
- Retry the whole pin/unpin if verification shows the old user_state — the operation is idempotent
- Avoid issuing learning tools while the core is restarting
Defensive patterns
Strategy: retry
Try / catch
match tool_exec(&tool_name, args).await {
Err(e) if e.to_string().contains("re-read failed") => {
// the pin itself likely landed — confirm instead of blind retry
tool_exec("learning_get_facet", args).await // inspect user_state
}
other => other,
} Prevention
- On re-read failure, verify the applied user_state with learning_get_facet before retrying the pin
- Don't fire learning tools while the core is shutting down or restarting
When it happens
Trigger: Another connection takes the write lock between the UPDATE and the SELECT (e.g. a rebuild cycle starting mid-call); the memory client's store being shut down concurrently (core shutting down mid-tool); disk I/O error.
Common situations: Core shutdown or restart racing an in-flight pin tool call; aggressive scheduled stability cycles in small workspaces.
Related errors
- learning_update_facet: {e:#}
- learning_update_facet: upsert failed: {e:#}
- {tool}: set_user_state failed: {e:#}
- learning_forget_facet: {e:#}
- learning_forget_facet: upsert failed: {e:#}
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/1f452668d790a3c7.
Report an issue: GitHub.