windmill-labs/windmill · error

Unknown type `{s}`

Error message

Unknown type `{s}`

What it means

find_typ maps C# type AST nodes to Windmill parameter types. When the node is an identifier whose text matches none of the whitelisted primitive/BCL types (int, string, char, float, double, bool, decimal, object and their System.* equivalents), it rejects it with this error. Windmill only supports a fixed set of C# types for main-function signatures; any custom or unrecognized type name is refused.

Source

Thrown at backend/parsers/windmill-parser-csharp/src/lib.rs:121

    match typ_node.kind() {
        "predefined_type" => {
            match typ_node.utf8_text(code.as_bytes()) {
                Ok("string") => Ok(Typ::Str(None)),
                Ok("sbyte") | Ok("System.SByte") => Ok(Typ::Bytes),
                Ok("byte") | Ok("System.Byte") => Ok(Typ::Bytes),
                Ok("short") | Ok("System.Int16") => Ok(Typ::Int),
                Ok("ushort") | Ok("System.UInt16") => Ok(Typ::Int),
                Ok("int") | Ok("System.Int32") => Ok(Typ::Int),
                Ok("uint") | Ok("System.UInt32") => Ok(Typ::Int),
                Ok("long") | Ok("System.Int64") => Ok(Typ::Int),
                Ok("ulong") | Ok("System.UInt64") => Ok(Typ::Int),
                Ok("char") | Ok("System.Char") => Ok(Typ::Str(None)),
                Ok("float") | Ok("System.Single") => Ok(Typ::Float),
                Ok("double") | Ok("System.Double") => Ok(Typ::Float),
                Ok("bool") | Ok("System.Boolean") => Ok(Typ::Bool),
                Ok("decimal") | Ok("System.Decimal") => Ok(Typ::Float),
                Ok("object") => Ok(Typ::Object(ObjectType::new(None, Some(vec![])))), // TODO: Complete the object type
                Ok(s) => Err(anyhow!("Unknown type `{s}`")),
                Err(e) => Err(anyhow!("Error getting type name: {}", e)),
            }
        }
        "array_type" => {
            let new_typ_node = typ_node
                .child_by_field_name("type")
                .ok_or(anyhow!("Failed to find inner type of array type"))?;
            Ok(Typ::List(Box::new(find_typ(new_typ_node, code)?)))
        }
        "identifier" => Ok(Typ::Unknown),
        "generic_name" => Ok(Typ::Unknown),
        "pointer_type" => Ok(Typ::Int),
        "nullable_type" => {
            let new_typ_node = typ_node
                .child_by_field_name("type")
                .ok_or(anyhow!("Failed to find inner type of nullable_type"))?;
            Ok(find_typ(new_typ_node, code)?)
        }

View on GitHub (pinned to e474e8803c)

Solutions

  1. Change the main-signature parameter to a supported type: int, string, char, float, double, bool, decimal, object, or an array/list of those
  2. For custom types, accept `object` in the signature and deserialize inside the script body
  3. If the type is a common alias (uint, long, ulong, short, byte), extend the match arms in find_typ to map it to an existing Typ
  4. File an issue upstream if you believe the type should be supported

Example fix

// before
static void Main(long count)
// after
static void Main(int count)
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check main-signature parameter types against the supported set before deploying
const SUPPORTED: &[&str] = &["int","string","char","float","double","bool","decimal","object","System.Int32","System.String","System.Char","System.Single","System.Double","System.Boolean","System.Decimal"];
fn unsupported_types(main_params: &[&str]) -> Vec<&str> {
    main_params.iter().filter(|t| !SUPPORTED.contains(t)).cloned().collect()
}

Type guard

fn is_supported_cs_type(t: &str) -> bool {
    matches!(t, "int" | "string" | "char" | "float" | "double" | "bool" | "decimal" | "object"
        | "System.Int32" | "System.String" | "System.Char" | "System.Single"
        | "System.Double" | "System.Boolean" | "System.Decimal")
}

Try / catch

match parse_csharp_signature(code) {
    Ok(sig) => sig,
    Err(e) if e.to_string().starts_with("Unknown type") => {
        // degrade gracefully: fall back to a default signature instead of failing deploy
        Ok(MainArgSignature::default())
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: A C# script whose `static void Main(...)` declares a parameter with a type that is not in the whitelist: custom classes, enums, structs, type aliases like `uint`, `long`, `short`, `byte`, `Int64`, `DateTime`, `Guid`, etc.

Common situations: Writing a Windmill C# script with `long count`, `uint id`, `DateTime start`, `Guid orderId`, `MyEnum status`; copy-pasting normal C# code into Windmill without adapting signature types to the supported set.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/81a786b21353f192. Report an issue: GitHub.