{"record":{"id":"85dbca38b02397fc","repo":"affaan-m/ECC","slug":"context-graph-observation-type-cannot-be-empty","errorCode":null,"errorMessage":"Context graph observation type cannot be empty","messagePattern":"Context graph observation type cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/session/store.rs","lineNumber":3380,"sourceCode":"        Ok(Some(ContextGraphEntityDetail {\n            entity,\n            outgoing,\n            incoming,\n        }))\n    }\n\n    pub fn add_context_observation(\n        &self,\n        session_id: Option<&str>,\n        entity_id: i64,\n        observation_type: &str,\n        priority: ContextObservationPriority,\n        pinned: bool,\n        summary: &str,\n        details: &BTreeMap<String, String>,\n    ) -> Result<ContextGraphObservation> {\n        if observation_type.trim().is_empty() {\n            return Err(anyhow::anyhow!(\n                \"Context graph observation type cannot be empty\"\n            ));\n        }\n        if summary.trim().is_empty() {\n            return Err(anyhow::anyhow!(\n                \"Context graph observation summary cannot be empty\"\n            ));\n        }\n\n        let now = chrono::Utc::now().to_rfc3339();\n        let details_json = serde_json::to_string(details)?;\n        self.conn.execute(\n            \"INSERT INTO context_graph_observations (\n                session_id, entity_id, observation_type, priority, pinned, summary, details_json, created_at\n             ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)\",\n            rusqlite::params![\n                session_id,\n                entity_id,","sourceCodeStart":3362,"sourceCodeEnd":3398,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/session/store.rs#L3362-L3398","documentation":"add/upsert of a context-graph observation validates observation_type first: a blank (after trim) type raises `Context graph observation type cannot be empty`. The type categorizes observations (e.g. \"note\", \"error\", \"decision\") and must be non-empty.","triggerScenarios":"Calling the observation API with observation_type = \"\" or \"  \" — typically when the type is derived from a plugin/category field that is optional or defaulted to empty.","commonSituations":"Importing observations from external logs without a category field; UI submissions with an unset type selector mapped to empty string; scripted bulk inserts missing the column.","solutions":["Supply an explicit observation type constant for each insert site.","Default to a well-known catch-all type (e.g. \"general\") instead of empty when the source lacks a category.","Validate/trim at the call boundary and reject or skip blank types.","Fix upstream mapping so optional categories become Option<String>, not empty strings."],"exampleFix":"// before\nlet kind = source_category.unwrap_or(\"\");\nstore.add_context_graph_observation(session_id, kind, priority, pinned, &summary, &details)?;\n// after\nlet kind = source_category.unwrap_or(\"general\");\nstore.add_context_graph_observation(session_id, kind, priority, pinned, &summary, &details)?;","handlingStrategy":"validation","validationCode":"const kind = (observationType ?? 'general').trim() || 'general';\nawait api.addContextGraphObservation(sessionId, kind, priority, pinned, summary, details);","typeGuard":"function hasObservationType(v) { return typeof v === 'string' && v.trim().length > 0; }","tryCatchPattern":"try {\n    store.add_context_graph_observation(session_id, &kind, priority, pinned, &summary, &details)?;\n} catch (e) {\n    if (String(e).includes('observation type cannot be empty')) {\n        // retry with fallback category\n        store.add_context_graph_observation(session_id, \"general\", priority, pinned, &summary, &details)?;\n    } else throw e;\n}","preventionTips":["Use enum/constant observation types instead of free-form strings where possible.","Default missing categories to a named fallback, never empty string.","Trim before calling; reject blank types at the API boundary.","Document required observation fields for plugin authors."],"tags":["context-graph","observation","validation","empty-field"],"backgroundTag":"empty-required-field","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}