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
- Read the body in the error — it is the core's answer and names the real problem
- If 401-after-restart: the next periodic tick re-authenticates; restart the app if it persists
- Resolve storage-side causes the core reports (free disk, clear db locks)
- 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
- keep upserts keyed/idempotent so retries and replays are safe
- expect 401 windows around in-process core restarts; degrade, do not crash
- alert on repeated per-tick upsert failures rather than one-off losses
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
- config_get http {}
- ${method}: HTTP ${res.status} ${await res.text()}
- OpenHuman could not reach its local runtime. Quit and reopen
- audio blob is empty
- voice_not_compiled
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/933c91e95e91e1f4.
Report an issue: GitHub.