the-benchmarker/web-frameworks · critical

Failed to parse app.zl

Error message

Failed to parse app.zl

What it means

zeno-rs-actix's main loads app.zl (from disk, falling back to the copy compiled in via include_str!) and parses it with parse_string; the .expect panics with "Failed to parse app.zl" if the Zeno DSL source is syntactically invalid, aborting server startup before the route map can be built.

Solutions

  1. Run the parser/CLI directly on app.zl to get the line/column of the syntax error and fix the DSL source
  2. Diff app.zl against the last known-good version (git diff) to spot accidental edits or merge remnants
  3. If a stale app.zl sits in the working directory, delete or fix it so the valid include_str! fallback is not shadowed by a broken file
  4. After upgrading the engine crate, update app.zl to the current DSL grammar
  5. Temporarily replace expect with error propagation/logging that prints the parse diagnostic before exiting

Example fix

// before
let main_node = parse_string(&zl_content, "app.zl").expect("Failed to parse app.zl");

// after
let main_node = parse_string(&zl_content, "app.zl")
    .unwrap_or_else(|e| {
        eprintln!("app.zl parse error: {e}");
        std::process::exit(1);
    });
Defensive patterns

Strategy: validation

Validate before calling

// before starting the server, syntax-check app.zl
match std::fs::read_to_string("app.zl")
    .or_else(|_| Ok::<_, std::io::Error>(include_str!("../app.zl").to_string()))
{
    Ok(content) => {
        if let Err(e) = zeno::parse_string(&content, "app.zl") {
            eprintln!("app.zl is invalid, refusing to start: {e:?}");
            std::process::exit(1);
        }
    }
    Err(e) => {
        eprintln!("cannot read app.zl: {e}");
        std::process::exit(1);
    }
}

Type guard

null

Try / catch

// main panics on parse failure; if embedding, isolate the parse step
let main_node = match std::panic::catch_unwind(|| parse_string(&zl_content, "app.zl")) {
    Ok(Ok(node)) => node,
    Ok(Err(e)) => { eprintln!("app.zl parse error: {e:?}"); std::process::exit(1); }
    Err(_) => { eprintln!("parser panicked while parsing app.zl"); std::process::exit(1); }
};

Prevention

When it happens

Trigger: Running the actix server binary when app.zl in the working directory (or the bundled ../app.zl fallback) contains DSL syntax errors, or when the file is read successfully but parse_string returns an Err for the 'app.zl' source name.

Common situations: A developer hand-edited app.zl and introduced a syntax error; an incomplete merge left the file malformed; the wrong app.zl was copied into the container working directory, shadowing a valid build-time one; DSL grammar changed in a library upgrade so older .zl files no longer parse.

Understand the failure class

Related errors


AI-assisted analysis of the-benchmarker/web-frameworks@3795a31d72 (2026-09-15). Data as JSON: /api/errors/5c3b408d67160031. Report an issue: GitHub.

Appendix: source

Thrown at rust/zeno-rs-actix/src/main.rs:174

    let r_post = routes.clone();
    engine.register(
        "http.post",
        Arc::new(move |_, _, node, _| {
            let raw = node.value.clone().unwrap_or_default().trim().to_string();
            let clean = if raw.starts_with('\'') || raw.starts_with('"') {
                raw[1..raw.len() - 1].to_string()
            } else {
                raw
            };
            r_post.lock().unwrap().push(("POST".to_string(), clean, node.clone()));
            Ok(())
        }),
        empty_slot_meta(),
    );

    let zl_content = std::fs::read_to_string("app.zl")
        .unwrap_or_else(|_| include_str!("../app.zl").to_string());
    let main_node = parse_string(&zl_content, "app.zl").expect("Failed to parse app.zl");

    let parent_scope = Scope::new(None);
    let mut init_ctx = Context::new();
    let _ = engine.execute(&mut init_ctx, &main_node, &parent_scope);

    let mut route_map: HashMap<String, MethodHandler> = HashMap::new();
    for (method, path, node) in routes.lock().unwrap().drain(..) {
        let matchit_path = convert_path_to_matchit(&path);
        println!("Registered route: {} {} -> matchit: {}", method, path, matchit_path);
        let entry = route_map
            .entry(matchit_path)
            .or_insert(MethodHandler { get: None, post: None });
        if method == "GET" {
            entry.get = Some(node);
        } else if method == "POST" {
            entry.post = Some(node);
        }
    }

View on GitHub (pinned to 3795a31d72)