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
- Validate relation_type is non-empty after trim at the call site; require a known vocabulary term.
- During import, skip rows with empty types or map to a default like "related_to".
- 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
- Wrap relation_type in a validating newtype; optionally enforce a controlled vocabulary.
- Skip blank-type edges during import.
- Require a relation type at the UI layer.
- Co-locate validation so the store never receives empty types.
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
- Context graph entity type cannot be empty
- Context graph entity name cannot be empty
- Context graph observation type cannot be empty
- Context graph observation summary cannot be empty
- Invalid session state transition: {} -> {}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/cc36d3499860073e.
Report an issue: GitHub.