tinyhumansai/openhuman · warning · anyhow::Error
Task source '{id}' not found.
Error message
Task source '{id}' not found. What it means
Thrown by `task_sources::store::remove_source` when `DELETE FROM task_sources WHERE id = ?1` reports zero changed rows — the id was not present to begin with. It is a guard so callers can distinguish 'deleted' from 'nothing was there'. The `Failed to delete task source` context on the SQL error itself is a different, lower-level failure; this message means the DELETE executed fine but matched nothing.
Source
Thrown at src/openhuman/integrations/task_sources/store.rs:223
i64::from(source.max_tasks_per_fetch),
source.assigned_executor,
id,
],
)
.context("Failed to update task source")?;
Ok(())
})?;
get_source(config, id)
}
pub fn remove_source(config: &Config, id: &str) -> Result<()> {
let changed = with_connection(config, |conn| {
conn.execute("DELETE FROM task_sources WHERE id = ?1", params![id])
.context("Failed to delete task source")
})?;
if changed == 0 {
anyhow::bail!("Task source '{id}' not found");
}
Ok(())
}
/// Update a source's `last_fetch_at` / `last_status` after a fetch pass.
pub fn record_fetch(
config: &Config,
id: &str,
finished_at: DateTime<Utc>,
reason: FetchReason,
status: &str,
) -> Result<()> {
let line = format!("{}: {status}", reason.as_str());
with_connection(config, |conn| {
conn.execute(
"UPDATE task_sources SET last_fetch_at = ?1, last_status = ?2 WHERE id = ?3",
params![finished_at.to_rfc3339(), line, id],
)View on GitHub (pinned to 7491200858)
Solutions
- Treat 'not found' on delete as success if your operation is idempotent — catch and match the message.
- Refresh source ids via `list_sources` before showing/issuing delete actions.
- Guard double-submits in the UI (disable the delete button after first click).
- If the delete should always match, audit for another actor deleting concurrently.
Example fix
// before
store::remove_source(&config, &id)?;
// after — idempotent delete
match store::remove_source(&config, &id) {
Ok(()) => Ok(()),
Err(e) if e.to_string().contains("not found") => Ok(()), // already gone
Err(e) => Err(e),
} Defensive patterns
Strategy: try-catch
Validate before calling
let still_there = task_sources::store::list_sources(&config)?
.iter().any(|s| s.id == id);
if !still_there { /* already deleted; nothing to do */ } Try / catch
match task_sources::store::remove_source(&config, &id) {
Ok(()) => Ok(()),
Err(e) if e.to_string().contains("not found") => Ok(()), // idempotent delete
Err(e) => Err(e),
} Prevention
- Make delete flows idempotent: swallow 'not found' as success.
- Disable delete buttons after the first click to avoid double-submits.
- Reconcile UI lists with list_sources after deletions.
When it happens
Trigger: `remove_source(config, id)` with an already-deleted id, a double-submit of a delete RPC, or concurrent deletion (two actors racing to remove the same source).
Common situations: Idempotent-looking retry UIs that re-send the delete after a timeout when the first attempt actually succeeded; UI list state gone stale; cleanup loops that iterate ids collected before another process deleted them.
Related errors
- Task source '{id}' not found
- MCP server '{}' not found
- memory file not found: ${path}
- Not running in Tauri
- OpenClaw memories table found but no content-like column was
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/eaae06a997f183a7.
Report an issue: GitHub.