affaan-m/ECC · error
Context graph observation summary cannot be empty
Error message
Context graph observation summary cannot be empty
What it means
The observation write path also requires a non-empty (trimmed) summary; a blank summary raises `Context graph observation summary cannot be empty`. The summary is the human-readable payload of the observation, so storing an empty one is treated as invalid input.
Solutions
- Skip recording observations that have no summary content.
- Generate a fallback summary (e.g. event name + timestamp) when the source text is empty.
- Validate at the boundary: trim and check non-empty before calling the store.
- Fix the upstream producer so it never emits blank summaries.
Example fix
// before
store.add_context_graph_observation(session_id, kind, priority, pinned, &generated, &details)?;
// after
let summary = if generated.trim().is_empty() {
format!("{kind} at {}", chrono::Utc::now().to_rfc3339())
} else { generated.trim().to_string() };
store.add_context_graph_observation(session_id, kind, priority, pinned, &summary, &details)?; Defensive patterns
Strategy: validation
Validate before calling
const s = summary.trim(); if (!s) return; // nothing to record await api.addContextGraphObservation(sessionId, type, priority, pinned, s, details);
Type guard
function hasSummary(v) { return typeof v === 'string' && v.trim().length > 0; } Try / catch
try {
store.add_context_graph_observation(session_id, &kind, priority, pinned, &summary, &details)?;
} catch (e) {
if (String(e).includes('observation summary cannot be empty')) {
log::warn!("dropped observation with blank summary");
} else throw e;
} Prevention
- Skip observations whose source produced no text instead of storing empty ones.
- Generate a descriptive fallback summary (kind + timestamp) for blank inputs.
- Check summarizer output for emptiness before calling the store.
- Trim summaries at the ingestion boundary consistently.
When it happens
Trigger: Recording an observation whose summary is "" or whitespace — e.g. summarizing an event that produced no text, or piping empty log messages into observations.
Common situations: Auto-summarizers returning empty output for empty diffs; log shippers forwarding empty lines; templates interpolating an unset variable into the summary.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Context graph observation type cannot be empty
- Context graph entity name cannot be empty
- Context graph entity type cannot be empty
- Context graph relation type cannot be empty
- -32602
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/e32055064efe9bc8.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/session/store.rs:3385
}
pub fn add_context_observation(
&self,
session_id: Option<&str>,
entity_id: i64,
observation_type: &str,
priority: ContextObservationPriority,
pinned: bool,
summary: &str,
details: &BTreeMap<String, String>,
) -> Result<ContextGraphObservation> {
if observation_type.trim().is_empty() {
return Err(anyhow::anyhow!(
"Context graph observation type cannot be empty"
));
}
if summary.trim().is_empty() {
return Err(anyhow::anyhow!(
"Context graph observation summary cannot be empty"
));
}
let now = chrono::Utc::now().to_rfc3339();
let details_json = serde_json::to_string(details)?;
self.conn.execute(
"INSERT INTO context_graph_observations (
session_id, entity_id, observation_type, priority, pinned, summary, details_json, created_at
) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
rusqlite::params![
session_id,
entity_id,
observation_type.trim(),
priority.as_db_value(),
pinned as i64,
summary.trim(),
details_json,View on GitHub (pinned to 8321021c54)