rust-lang/rust-analyzer · error

Failed to make expr node `{node}` from text `{text}`

Error message

Failed to make expr node `{node}` from text `{text}`

What it means

`expr_from_text(_with_edition)` in `syntax::ast::make` parses the snippet as a Rust expression and casts the first descendant matching type `E`. If the parse yields no node of the expected expression type, it panics naming the type and the offending text. This is an internal invariant failure: an `make::expr_*` constructor was given text that does not produce the expected expression node.

Source

Thrown at crates/syntax/src/ast/make.rs:1386

}

pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
    expr_from_text(&format!("while let {pattern} = {expr} {{}}"))
}

#[track_caller]
fn expr_from_text<E: Into<ast::Expr> + AstNode>(text: &str) -> E {
    expr_from_text_with_edition(text, Edition::CURRENT)
}

#[track_caller]
fn expr_from_text_with_edition<E: Into<ast::Expr> + AstNode>(text: &str, edition: Edition) -> E {
    let parse = ast::Expr::parse(text, edition);
    let node = match parse.tree().syntax().descendants().find_map(E::cast) {
        Some(it) => it,
        None => {
            let node = std::any::type_name::<E>();
            panic!("Failed to make expr node `{node}` from text `{text}`")
        }
    };
    let node = node.clone_subtree();
    assert_eq!(node.syntax().text_range().start(), 0.into());
    node
}

#[track_caller]
fn ast_from_text<N: AstNode>(text: &str) -> N {
    ast_from_text_with_edition(text, Edition::CURRENT)
}

#[track_caller]
fn ast_from_text_with_edition<N: AstNode>(text: &str, edition: Edition) -> N {
    let parse = SourceFile::parse(text, edition);
    let node = match parse.tree().syntax().descendants().find_map(N::cast) {
        Some(it) => it,
        None => {

View on GitHub (pinned to e8f7e90aa3)

Solutions

  1. Check `{text}` in the panic message and ensure it is a single well-formed Rust expression of the type named by `{node}`.
  2. Verify the fragment by running `ast::Expr::parse(text, edition)` and inspecting `parse.errors()` before constructing nodes.
  3. If text comes from user code, sanitize/validate it (extract via parsing and re-serialize) instead of passing raw text.
  4. Confirm the correct `Edition`; use the `_with_edition` variant explicitly for edition-sensitive syntax.

Example fix

// before (panics: `let x = 1;` is not an expr)
let e = make::expr_call(f, ta(make::expr_from_text("let x = 1;")));
// after
let e = make::expr_call(f, ta(make::expr_from_text("1 + 2")));
Defensive patterns

Strategy: validation

Validate before calling

fn expr_text_is_valid(text: &str, edition: span::Edition) -> bool {
    let parse = syntax::ast::Expr::parse(text, edition);
    parse.errors().is_empty()
        && parse.syntax().first_child_or_token().is_some()
}

Type guard

fn as_expr_node<N: Into<syntax::ast::Expr> + syntax::AstNode>(
    text: &str,
    edition: span::Edition,
) -> Option<N> {
    let parse = syntax::ast::Expr::parse(text, edition);
    parse.tree().syntax().descendants().find_map(N::cast)
}

Prevention

When it happens

Trigger: Calling a `make::expr_*` constructor with text that parses to a different syntactic category than `E` or fails to parse entirely (empty string, a statement like `let x = 1;`, a type, or edition-invalid syntax), so `E::cast` finds nothing.

Common situations: Interpolating untrusted or user-edited source text into `format!` templates fed to make constructors; assist/fix logic generating empty or malformed fragments; edition mismatches where the expression is only valid in one edition.

Related errors


AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03). Data as JSON: /api/errors/942c922c148b393b. Report an issue: GitHub.