zed-industries/zed · error
operands of == must be identifiers
Error message
operands of == must be identifiers
What it means
new_eq builds an Equal predicate only when both operands parsed as plain Identifiers — the only shape evaluation supports (it resolves the left identifier's value and compares it to the right). If either side is a composite (parenthesized group, &&/|| chain, '>' descendant, or negation), the constructor bails. Comparisons in this DSL are always identifier-to-identifier.
Source
Thrown at crates/gpui/src/keymap/context.rs:435
}
fn new_or(self, other: Self) -> Result<Self> {
Ok(Self::Or(Box::new(self), Box::new(other)))
}
fn new_and(self, other: Self) -> Result<Self> {
Ok(Self::And(Box::new(self), Box::new(other)))
}
fn new_child(self, other: Self) -> Result<Self> {
Ok(Self::Descendant(Box::new(self), Box::new(other)))
}
fn new_eq(self, other: Self) -> Result<Self> {
if let (Self::Identifier(left), Self::Identifier(right)) = (self, other) {
Ok(Self::Equal(left, right))
} else {
anyhow::bail!("operands of == must be identifiers");
}
}
fn new_neq(self, other: Self) -> Result<Self> {
if let (Self::Identifier(left), Self::Identifier(right)) = (self, other) {
Ok(Self::NotEqual(left, right))
} else {
anyhow::bail!("operands of != must be identifiers");
}
}
fn fmt_joined(
&self,
f: &mut fmt::Formatter<'_>,
separator: &str,
operator: LogicalOperator,
needs_parens: impl Fn(&Self) -> bool + Copy,
) -> fmt::Result {View on GitHub (pinned to f4178619ac)
Solutions
- Keep both sides of == as bare identifiers: mode == visual
- Expand alternatives into a chain: (mode == normal || mode == visual) instead of mode == (normal || visual)
- Move composite logic outside the comparison and combine results with && or ||
Example fix
// before (keymap.json) "context": "mode == (normal || visual)" // after "context": "(mode == normal || mode == visual)"
Defensive patterns
Strategy: validation
Validate before calling
KeyBindingContextPredicate::parse("(mode == normal || mode == visual)")?; // validate before install Type guard
fn is_parseable_context(source: &str) -> bool {
KeyBindingContextPredicate::parse(source).is_ok()
} Prevention
- Remember == and != combine identifiers only
- Expand alternatives into || chains of whole comparisons
- Parenthesize composite operands away from comparisons
When it happens
Trigger: Writing '(a && b) == c', 'mode == (normal || visual)', or 'A > B == c' — any == whose left or right operand is not a single identifier.
Common situations: Trying to compare against a group of alternatives on the right-hand side; adding precedence parentheses around one side of a comparison; copying boolean expression shapes from other keymap formats.
Related errors
- operands of != must be identifiers
- unexpected character '{next:?}'
- invalid RGBA hex color: '{value}'. Expected #rgb, #rgba, #rr
- Device lost: {err}
- database not initialized
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/c9917f4d2f78e888.
Report an issue: GitHub.