tinyhumansai/openhuman · warning

{tool}: facet not found: {fk}

Error message

{tool}: facet not found: {fk}

What it means

Thrown by set_pin (learning_pin_facet / learning_unpin_facet) when set_user_state returned Ok(false) — the UPDATE on user_profile matched zero rows, so no facet exists with the composed full key '{class}/{key}'. This is a semantic not-found, not a storage failure: the class prefix or key suffix does not match any row, or the facet was evicted/deleted earlier.

Source

Thrown at src/openhuman/agent/learning/tools.rs:275

        }))?))
    }
}

/// 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"
    }

View on GitHub (pinned to a221052e0d)

Solutions

  1. Call learning_list_facets (optionally filtered by class) and pin using a key verbatim from the result
  2. If the list is empty or the facet is missing, re-derive it via learning_rebuild_cache or normal conversation before pinning
  3. Check exact spelling and the class prefix — keys are 'class/suffix' strings and the class must match FacetClass vocabulary

Example fix

// before: guessed key
tool: learning_pin_facet {"class":"style","key":"tone"} // -> facet not found: style/tone
// after: list first, use verbatim key
tool: learning_list_facets {"class":"style"}     // returns key "style/verbosity"
tool: learning_pin_facet {"class":"style","key":"verbosity"}
Defensive patterns

Strategy: validation

Validate before calling

// Resolve the real key from the cache before pinning:
let facets = tool_exec("learning_list_facets", json!({"class": class})).await?; // returns keys like "style/verbosity"
let suffix = facets.iter().find(|f| f.key == format!("{class}/{key}"))
    .ok_or_else(|| anyhow::"facet {class}/{key} not in cache — re-derive it first")?;
tool_exec("learning_pin_facet", json!({"class": class, "key": key})).await

Type guard

fn known_facet_key(listed: &[String], class: &str, key: &str) -> bool {
    listed.iter().any(|k| k == &format!("{class}/{key}"))
}

Try / catch

match tool_exec("learning_pin_facet", args).await {
    Err(e) if e.to_string().contains("facet not found") => {
        let listed = tool_exec("learning_list_facets", json!({})).await?; // refresh, pick verbatim key
        /* re-issue with a key from `listed` or surface to the user */
        unimplemented!()
    }
    other => other,
}

Prevention

When it happens

Trigger: Pinning/unpinning with a class/key pair the agent invented instead of one returned by learning_list_facets; the facet was evicted by a stability rebuild (drop_below_threshold) or removed by learning_reset_cache (non-pinned facets are deleted) between listing and pinning; whitespace/format drift in the key suffix.

Common situations: LLM hallucinating plausible facet keys like 'style/tone' when the cache holds 'style/verbosity'; acting on a stale facet list from earlier in a long session; pinning after the user reset the cache.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/e7ae3770c064d96d. Report an issue: GitHub.