windmill-labs/windmill · error
Failed to parse code
Error message
Failed to parse code
What it means
parse_csharp_sig_meta parses C# source with tree-sitter to find the Main method signature and derive the script kind. parser.parse(code, None) returns a tree that is unwrapped with .expect("Failed to parse code"), which panics when the tree-sitter parse produces no tree (allocation/parse failure). Despite the message wording, most malformed C# still yields a tree — this expect fires on hard parse failures, and downstream find_main_signature returns None for code without Main.
Source
Thrown at backend/parsers/windmill-parser-csharp/src/lib.rs:35
pub class_name: Option<String>,
pub main_sig: MainArgSignature,
}
fn csharp_param_default_value<'a>(def: Node<'a>, code: &str) -> Option<serde_json::Value> {
def.utf8_text(code.as_bytes())
.ok()
.and_then(|content| serde_json::from_str(content).ok())
}
pub fn parse_csharp_sig_meta(code: &str) -> anyhow::Result<CsharpMainSigMeta> {
let mut parser = tree_sitter::Parser::new();
let language = tree_sitter_c_sharp::LANGUAGE;
parser
.set_language(&language.into())
.map_err(|e| anyhow!("Error setting c# as language: {e}"))?;
// Parse code
let tree = parser.parse(code, None).expect("Failed to parse code");
let root_node = tree.root_node();
// Traverse the AST to find the Main method signature
let main_sig = find_main_signature(root_node, code);
let auto_kind = if main_sig.is_none() {
Some("lib".to_string())
} else {
None
};
let mut is_async = false;
let mut is_public = false;
let mut returns_void = false;
let mut class_name = None;
let mut args = vec![];
if let Some((sig, name)) = main_sig {
class_name = name;
for sig_node in sig.children(&mut sig.walk()) {View on GitHub (pinned to e474e8803c)
Solutions
- Validate the C# source compiles/parses locally (dotnet build or a C# linter) before uploading.
- Ensure the script content is complete, UTF-8 text and non-empty.
- If parsing valid code, pin/update tree-sitter-c-sharp to a version matching the tree-sitter runtime in Cargo.lock.
- In code, replace the expect with graceful error handling so malformed scripts report a user-facing validation error instead of panicking.
Example fix
// before
let tree = parser.parse(code, None).expect("Failed to parse code");
// after
let tree = parser
.parse(code, None)
.ok_or_else(|| anyhow!("Failed to parse code"))?; Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the C# source is non-empty, UTF-8 text before calling the parser
fn is_plausible_csharp(code: &str) -> bool {
!code.trim().is_empty() && code.is_char_boundary(0)
} Try / catch
// The call panics via expect, so run it on an isolated thread if callers must survive:
let result = std::panic::catch_unwind(|| parse_csharp_sig_meta(code));
match result {
Ok(Ok(meta)) => meta,
_ => return Err(anyhow!("C# script could not be parsed; check syntax")),
} Prevention
- Validate C# syntax (dotnet build/linter) before uploading scripts
- Ensure script content is complete, non-empty UTF-8 text
- Pin tree-sitter-c-sharp to a version compatible with the tree-sitter runtime
When it happens
Trigger: Calling parse_csharp_signature/parse_csharp_sig_meta (script upload/analysis path for csharp scripts) where tree_sitter cannot produce a parse tree for the supplied code.
Common situations: Uploading a C# script with severely malformed/truncated source, non-UTF8 or binary content, or an empty payload; a tree-sitter-c-sharp grammar/runtime mismatch after dependency updates.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Error getting type name: {}
- Failed to parse Cargo.toml.default
- no policy could be derived for runnable(s) ${malformed.join(
- Error parsing yaml ${path}
- AI response contained empty code block
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/8288616e27b736f6.
Report an issue: GitHub.