tinyhumansai/openhuman · error · anyhow::Error

core rpc {}: {}

Error message

core rpc {}: {}

What it means

The scanner's memory-upsert step POSTs an already-built memory-doc payload to the core's /rpc; a non-success status bails with `core rpc <status>: <body>`. The chat.db scan succeeded — the failure is between the Tauri shell and the local core, and the upserted day is not persisted this tick.

Source

Thrown at app/src-tauri/src/imessage_scanner/mod.rs:452

            "key": key,
            "title": format!("Messages — {} — {}", chat_id, day),
            "content": transcript,
            "source_type": "imessage",
            "tags": ["chat", "imessage"],
            "metadata": {
                "chat_identifier": chat_id,
                "day": day,
                "source": "imessage"
            },
            "category": "chat"
        }
    });

    let req = crate::core_rpc::apply_auth(http_client().post(&url)).map_err(anyhow::Error::msg)?;
    let res = req.json(&body).send().await?;

    if !res.status().is_success() {
        anyhow::bail!("core rpc {}: {}", res.status(), res.text().await?);
    }

    log::info!("[imessage] memory upsert ok key={}", key);
    Ok(())
}

// Non-macOS stub so the rest of the app compiles unchanged.
#[cfg(not(target_os = "macos"))]
pub struct ScannerRegistry;

#[cfg(not(target_os = "macos"))]
impl ScannerRegistry {
    pub fn new() -> Self {
        Self
    }
    pub fn shutdown(&self) {}
}

View on GitHub (pinned to a221052e0d)

Solutions

  1. Read the body in the error — it is the core's answer and names the real problem
  2. If 401-after-restart: the next periodic tick re-authenticates; restart the app if it persists
  3. Resolve storage-side causes the core reports (free disk, clear db locks)
  4. Rely on keyed, idempotent upserts: re-running the scan replays the missed day safely

Example fix

// before
let res = req.json(&body).send().await?;
if !res.status().is_success() {
    anyhow::bail!("core rpc {}: {}", res.status(), res.text().await?);
}

// after — one bounded retry on 5xx before giving up the tick
let send = |b: serde_json::Value| async { crate::core_rpc::apply_auth(http_client().post(&url))
    .map_err(anyhow::Error::msg)?.json(&b).send().await };
let mut res = send(body.clone()).await?;
if res.status().as_u16() >= 500 { res = send(body).await?; }
if !res.status().is_success() {
    anyhow::bail!("core rpc {}: {}", res.status(), res.text().await?);
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight the core before a batch of upserts
if !core_rpc_reachable(&url).await {
    log::warn!("[imessage] core unreachable; deferring memory upsert to next tick");
    return Ok(());
}

Try / catch

for attempt in 0..2 {
    match upsert_memory_doc(&url, &body).await {
        Ok(()) => break,
        Err(e) if attempt == 0 && e.to_string().starts_with("core rpc 5") => continue,
        Err(e) if e.to_string().starts_with("core rpc 401") => {
            log::warn!("[imessage] stale auth; next tick re-authenticates"); break;
        }
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: Core restarted/restarting when the upsert fired (stale bearer → 401); core returned 500 while persisting memory (disk full, memory-store db lock); payload rejected by the RPC layer.

Common situations: App update restarting the in-process core while a scan finishes; storage pressure on the workspace; the same stale-token situations as error 292 but hitting the write path.

Related errors


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