zeroclaw-labs/zeroclaw · error

source node not found: {from_id}

Error message

source node not found: {from_id}

What it means

add_edge inserts into an edges table whose from_id/to_id have foreign keys to nodes(id) (ON DELETE CASCADE), but before inserting it explicitly checks both endpoints with SELECT COUNT(*) FROM nodes WHERE id = ?. If the source (from_id) row does not exist, it bails with this message naming the missing id. This is a referential-integrity rejection: edges may only connect nodes present in this same SQLite file.

Source

Thrown at crates/zeroclaw-memory/src/knowledge_graph.rs:268

        Ok(id)
    }

    /// Add a directed edge between two nodes.
    pub fn add_edge(&self, from_id: &str, to_id: &str, relation: Relation) -> anyhow::Result<()> {
        let conn = self.conn.lock();

        // Verify both endpoints exist.
        let exists = |id: &str| -> anyhow::Result<bool> {
            let c: usize = conn.query_row(
                "SELECT COUNT(*) FROM nodes WHERE id = ?1",
                params![id],
                |r| r.get(0),
            )?;
            Ok(c > 0)
        };

        if !exists(from_id)? {
            anyhow::bail!("source node not found: {from_id}");
        }
        if !exists(to_id)? {
            anyhow::bail!("target node not found: {to_id}");
        }

        conn.execute(
            "INSERT OR IGNORE INTO edges (from_id, to_id, relation) VALUES (?1, ?2, ?3)",
            params![from_id, to_id, relation.as_str()],
        )?;

        Ok(())
    }

    /// Retrieve a node by id.
    pub fn get_node(&self, id: &str) -> anyhow::Result<Option<KnowledgeNode>> {
        let conn = self.conn.lock();
        let mut stmt = conn.prepare(
            "SELECT id, node_type, title, content, tags, created_at, updated_at, source_project

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Create the source node first (keep the id add_node returned) and pass that exact id to add_edge.
  2. If the id came from elsewhere, verify it with get_node(from_id) — returning None confirms this error is imminent.
  3. If the graph database was recreated or migrated, re-register the node under a new id and update references before relating.
  4. Treat capture+relate as one unit: relate immediately after capture with the freshly returned id.

Example fix

// before
graph.add_edge("00000000-0000-0000-0000-000000000000", &expert_id, Relation::AuthoredBy)?; // source node not found

// after: use the id the graph itself issued
let pattern_id = graph.add_node(NodeType::Pattern, "t", "c", &[], None)?;
graph.add_edge(&pattern_id, &expert_id, Relation::AuthoredBy)?;
Defensive patterns

Strategy: validation

Validate before calling

// Verify endpoints before connecting
if graph.get_node(from_id)?.is_none() {
    return Err(anyhow::anyhow!("cannot relate: source node {from_id} does not exist"));
}
graph.add_edge(from_id, to_id, relation)?;

Type guard

pub fn can_connect(graph: &KnowledgeGraph, from_id: &str, to_id: &str) -> bool {
    graph.get_node(from_id).ok().flatten().is_some() && graph.get_node(to_id).ok().flatten().is_some()
}

Try / catch

// On capture+relate flows, recreate the missing endpoint instead of dropping the relation
match graph.add_edge(from_id, to_id, relation) {
    Ok(()) => {}
    Err(e) if e.to_string().contains("source node not found") => {
        let from_id = graph.add_node(node_type, title, content, tags, None)?;
        graph.add_edge(&from_id, to_id, relation)?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling add_edge (or the relate handler) with a from_id that was never created by add_node on this graph: a hand-typed or truncated UUID, an id returned by a different KnowledgeGraph/database file, or an id belonging to a node deleted earlier in the same flow (its edges cascade-deleted, and the node itself is gone).

Common situations: Persisting node ids in another store (notes, tickets) and reusing them against a rebuilt/moved graph DB; hardcoding ids in scripts; races where a capture's node was rolled back or pruned before the relate step; splitting capture and relate across processes pointed at different db paths.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/20ece8626f4ccdea. Report an issue: GitHub.