affaan-m/ECC · warning · anyhow::Error

Context graph relation type cannot be empty

Error message

Context graph relation type cannot be empty

What it means

Raised by upsert_context_relation in ecc2/src/session/store.rs:3673 when relation_type.trim().is_empty(). Relations are edges between context-graph entities with a unique constraint on (from_entity_id, to_entity_id, relation_type); an empty type would collide all relations between the same pair and lose semantic distinction, so it is rejected before the INSERT ... ON CONFLICT upsert.

Source

Thrown at ecc2/src/session/store.rs:3673

        Ok(ContextGraphCompactionStats {
            entities_scanned,
            duplicate_observations_deleted,
            overflow_observations_deleted,
            observations_retained,
        })
    }

    pub fn upsert_context_relation(
        &self,
        session_id: Option<&str>,
        from_entity_id: i64,
        to_entity_id: i64,
        relation_type: &str,
        summary: &str,
    ) -> Result<ContextGraphRelation> {
        let relation_type = relation_type.trim();
        if relation_type.is_empty() {
            return Err(anyhow::anyhow!(
                "Context graph relation type cannot be empty"
            ));
        }
        let summary = summary.trim();
        let timestamp = chrono::Utc::now().to_rfc3339();

        self.conn.execute(
            "INSERT INTO context_graph_relations (
                session_id, from_entity_id, to_entity_id, relation_type, summary, created_at
             )
             VALUES (?1, ?2, ?3, ?4, ?5, ?6)
             ON CONFLICT(from_entity_id, to_entity_id, relation_type) DO UPDATE SET
                session_id = COALESCE(excluded.session_id, context_graph_relations.session_id),
                summary = CASE
                    WHEN excluded.summary <> '' THEN excluded.summary
                    ELSE context_graph_relations.summary
                END",
            rusqlite::params![

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Validate relation_type is non-empty after trim at the call site; require a known vocabulary term.
  2. During import, skip rows with empty types or map to a default like "related_to".
  3. Co-locate validation so the store never receives empty types.

Example fix

// before
store.upsert_context_relation(Some(sid), from_id, to_id, "", summary)?;

// after: enforce a non-empty relation type
let relation_type = relation_type.trim();
if relation_type.is_empty() {
    anyhow::bail!("relation_type is required between {from_id} and {to_id}");
}
store.upsert_context_relation(Some(sid), from_id, to_id, relation_type, summary)?;
Defensive patterns

Strategy: validation

Validate before calling

// Validating newtype for relation_type, optionally against a vocabulary.
#[derive(Debug, Clone)]
pub struct RelationType(String);

impl RelationType {
    pub fn new(raw: &str) -> anyhow::Result<Self> {
        let trimmed = raw.trim();
        if trimmed.is_empty() {
            anyhow::bail!("relation type cannot be empty");
        }
        Ok(Self(trimmed.to_string()))
    }
    pub fn as_str(&self) -> &str { &self.0 }
}

let rtype = RelationType::new(raw)?;
store.upsert_context_relation(sid, from_id, to_id, rtype.as_str(), summary)?;

Type guard

// RelationType (above) is the type guard; it cannot represent an empty
// string. Optionally add a vocabulary check in the constructor.

Try / catch

for edge in relation_import {
    let rtype = match RelationType::new(&edge.relation_type) {
        Ok(r) => r,
        Err(_) => { tracing::warn!("skipping relation {} -> {} with empty type", edge.from, edge.to); continue; }
    };
    store.upsert_context_relation(sid, edge.from, edge.to, rtype.as_str(), &edge.summary)?;
}

Prevention

When it happens

Trigger: Passing relation_type = ""; importing edges where the type column is blank; programmatic relation creation where the type was supposed to be derived but the source was empty.

Common situations: Bulk import of relation data with sparse type columns; auto-derived relation types from a model that emitted nothing; UI forms that do not require a relation type.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/cc36d3499860073e. Report an issue: GitHub.