zeroclaw-labs/zeroclaw · error
unknown {}: {other}
Error message
unknown {}: {other} What it means
knowledge_graph.rs defines its enums (NodeType, Relation) with the knowledge_enum! macro, whose generated parse(s) accepts only the exact snake_case schema strings and bails with "unknown <label>: <value>" otherwise — the label is "node type" for NodeType and "relation" for Relation. Valid values: node types pattern|decision|lesson|expert|technology|client|contact|interaction; relations uses|replaces|extends|authored_by|applies_to|manages_client|contact_of|interacted_with. Because nodes and edges store these strings in SQLite columns and parse them back on read, a bad string in the DB or in caller/user input produces this error at parse time.
Source
Thrown at crates/zeroclaw-memory/src/knowledge_graph.rs:46
impl $name {
pub const ALL: &'static [Self] = &[$(Self::$variant),+];
pub const SCHEMA_VALUES: &'static [&'static str] = &[$($value),+];
pub fn as_str(&self) -> &'static str {
match self {
$(Self::$variant => $value),+
}
}
pub fn schema_values() -> &'static [&'static str] {
Self::SCHEMA_VALUES
}
pub fn parse(s: &str) -> anyhow::Result<Self> {
match s {
$($value => Ok(Self::$variant),)+
other => anyhow::bail!(
"unknown {}: {other}",
$error_label
),
}
}
}
};
}
knowledge_enum! {
/// The kind of knowledge captured in a node.
pub enum NodeType {
Pattern => "pattern",
Decision => "decision",
Lesson => "lesson",
Expert => "expert",
Technology => "technology",
Client => "client",View on GitHub (pinned to 88bb9c8533)
Solutions
- Pass one of the exact snake_case schema strings; use NodeType::SCHEMA_VALUES / Relation::SCHEMA_VALUES (or as_str on a known variant) instead of hand-typing the literal.
- Normalize input before parsing: trim, lowercase, and convert '-' or spaces to '_' for relation names.
- If the value came from a stored row, inspect the nodes/edges tables for the offending string and migrate or fix those rows to the current vocabulary.
- Pin your ZeroClaw version when moving graph databases between installs so enum vocabularies match.
Example fix
// before
let rel = Relation::parse("authored-by")?; // unknown relation: authored-by
// after
let rel = Relation::parse("authored_by")?;
// or derive from a typed value: Relation::AuthoredBy.as_str() Defensive patterns
Strategy: type-guard
Validate before calling
// Reject unknown values before touching the graph
fn normalize_relation(s: &str) -> Option<String> {
let norm = s.trim().to_lowercase().replace(['-', ' '], "_");
Relation::SCHEMA_VALUES.contains(&norm.as_str()).then_some(norm)
}
if normalize_relation(&input).is_none() {
return Err(anyhow::anyhow!("unsupported relation '{input}'; valid: {:?}", Relation::SCHEMA_VALUES));
} Type guard
pub fn is_known_node_type(s: &str) -> bool {
NodeType::SCHEMA_VALUES.contains(&s)
}
pub fn is_known_relation(s: &str) -> bool {
Relation::SCHEMA_VALUES.contains(&s)
} Try / catch
// Parse user/DB input defensively
match Relation::parse(&raw) {
Ok(rel) => graph.add_edge(&from, &to, rel)?,
Err(e) if e.to_string().starts_with("unknown relation") => {
tracing::warn!(raw, "skipping edge with unrecognized relation");
continue;
}
Err(e) => return Err(e),
} Prevention
- Never hand-build the literal; use Relation::AuthoredBy.as_str() or the SCHEMA_VALUES constants.
- Normalize (trim, lowercase, '-'→'_') any human or LLM input before parse.
- Validate stored vocabularies after version upgrades: SELECT DISTINCT node_type FROM nodes / DISTINCT relation FROM edges against SCHEMA_VALUES.
- Keep relation vocabulary pinned per database file; migrate strings when the enum set changes.
When it happens
Trigger: NodeType::parse or Relation::parse receiving anything outside the fixed set: "authored-by" or "authored by" instead of "authored_by", camelCase like "AuthoredBy", uppercase or whitespace-padded values, or a value from a user command routed through the graph's capture/relate handlers. Also triggered when a database row contains a node_type/relation written by a different (newer or older) ZeroClaw version whose vocabulary has drifted.
Common situations: Passing free-form user input straight to parse; scripts migrating a graph between versions; enum variants added or renamed between releases while the SQLite file persists old strings; JSON configs that cased the value differently than the serde snake_case mapping.
Related errors
- source node not found: {from_id}
- target node not found: {to_id}
- tool-channel-room-error-invalid-action
- cloud_ops.iac_tools must not be empty when cloud_ops is enab
- gateway.path_prefix contains invalid character '{bad}'; only
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/06fdf8cb6023dcd8.
Report an issue: GitHub.