tinyhumansai/openhuman · error
flow '{id}' not found
Error message
flow '{id}' not found What it means
remove_flow's DELETE FROM flow_definitions affected zero rows, so no flow had that id and the delete bails instead of pretending success. Like its cron twin, the affected-row-count check distinguishes 'deleted' from 'nothing there'.
Source
Thrown at src/openhuman/flows/store.rs:449
/// `ComposioTriggerReceived` event against every enabled `app_event` flow —
/// scanning the (small) enabled set once per event is simpler and cheap
/// enough at expected flow counts; a dedicated toolkit/trigger_slug index is
/// a later optimization if this ever shows up as a bottleneck.
///
/// Returns `(flows, skipped)` — see [`list_flows`]. A corrupt row here must
/// not take down `app_event` dispatch for every *other* enabled flow (R-M4).
pub fn list_enabled_flows(config: &Config) -> Result<(Vec<Flow>, usize)> {
with_connection(config, |conn| list_flow_rows(conn, "WHERE enabled = 1"))
}
/// Deletes a flow by id. Returns an error if no such flow exists.
pub fn remove_flow(config: &Config, id: &str) -> Result<()> {
let changed = with_connection(config, |conn| {
conn.execute("DELETE FROM flow_definitions WHERE id = ?1", params![id])
.context("Failed to delete flow definition")
})?;
if changed == 0 {
anyhow::bail!("flow '{id}' not found");
}
tracing::debug!(flow_id = %id, "[flows] removed flow definition");
Ok(())
}
/// Toggles a flow's `enabled` flag, returning the updated record.
pub fn set_enabled(config: &Config, id: &str, enabled: bool) -> Result<Flow> {
let now = Utc::now().to_rfc3339();
let changed = with_connection(config, |conn| {
conn.execute(
"UPDATE flow_definitions SET enabled = ?1, updated_at = ?2 WHERE id = ?3",
params![if enabled { 1 } else { 0 }, now, id],
)
.context("Failed to update flow enabled state")
})?;
if changed == 0 {
anyhow::bail!("flow '{id}' not found");
}View on GitHub (pinned to 7491200858)
Solutions
- List flows (flows.list) and confirm the id still exists; if gone, treat the delete as done
- Re-copy the id from the current listing if the flow exists under a different id
- Verify workspace/user profile if the listing itself is empty
Example fix
// before
await flowsApi.remove(flowId); // throws on already-deleted
// after
try { await flowsApi.remove(flowId); }
catch (e) { if (!isNotFoundFlowError(e)) throw e; } // idempotent delete Defensive patterns
Strategy: try-catch
Try / catch
try { await removeFlow(id); } catch (e) { if (isNotFoundFlowError(e)) return ok('already deleted'); throw e; } — classify by the 'flow ... not found' message and treat it as success for idempotent deletes. Prevention
- Make UI delete actions idempotent (accept not-found as success)
- Refresh the flow list after deletions from other tabs
- Guard against double-submits by disabling buttons during the in-flight request
When it happens
Trigger: flows.delete with a stale id (flow already removed from another session or tab); a typo'd id; a different workspace's flow store, which is per-workspace SQLite like cron.
Common situations: Double-submit of a delete button; retry after a timeout whose first attempt succeeded; scripts holding ids from an earlier listing; multiple open clients.
Related errors
- Cron job '{id}' not found
- Cron job '{job_id}' not found
- memory file not found: ${path}
- Missing schedule and legacy expression for cron job
- invalid draft id: {id:?}
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/8d5a5c1a674fa85b.
Report an issue: GitHub.