windmill-labs/windmill · error

typed tables are not supported, use `ident: table`

Error message

typed tables are not supported, use `ident: table`

What it means

Like typed records, Nushell typed tables (`table<col: type, ...>`) are not representable in Windmill's signature types. The parser maps bare `table` to a list of open objects, but any type containing `table<` bails with this message directing you to the untyped form.

Source

Thrown at backend/parsers/windmill-parser-nu/src/lib.rs:186

            "nothing" => Typ::Unknown,
            // TODO: needs additional work on literal parsing
            // "binary" => Typ::Bytes,
            "datetime" => Typ::Datetime,
            "any" => Typ::Unknown,
            "bool" => Typ::Bool,
            // Lists
            "list" | "list<any>" | "list<nothing>" => Typ::List(Box::new(Typ::Unknown)),
            "list<number>" => Typ::List(Box::new(Typ::Float)),
            "list<bool>" => Typ::List(Box::new(Typ::Bool)),
            "list<string>" => Typ::List(Box::new(Typ::Str(None))),
            // list<float/int> is not supported
            // Records and Tables
            // TODO: Support in V1?
            s if s.contains("record<") => {
                bail!("typed records are not supported, use `ident: record`")
            }
            s if s.contains("table<") => {
                bail!("typed tables are not supported, use `ident: table`")
            }
            s => bail!("{s} is not supported"),
        };
        Ok(typ)
    }
    fn parse_default(
        content: &str,
        ctx: &[&str],
        i: usize,
        skip: &mut usize,
    ) -> anyhow::Result<Value> {
        let mut c = content.replace("=", "").trim().to_owned();

        fn parse_object_literal(
            (open, close): (char, char),
            mut c_2: String,
            ctx: &[&str],
            i: usize,

View on GitHub (pinned to e474e8803c)

Solutions

  1. Change the annotation to bare `table` (list of objects) and validate columns in the script.
  2. Accept `list` or `any` and perform per-row checks in the body.
  3. Pass data as a JSON array of objects and normalize inside the script.
  4. Wrap row validation in a helper so the signature stays untyped while logic stays strict.

Example fix

// before
def main [rows: table<id: int, name: string>]
// after
def main [rows: table] {
  $rows | each {|r| {id: ($r.id | into int), name: $r.name}}
}
Defensive patterns

Strategy: validation

Validate before calling

function validateNoTypedTables(code) {
  const m = code.match(/def\s+main\s*\[([^\]]*)\]/);
  if (m && /table</.test(m[1])) return 'typed tables (table<...>) are not supported; use bare `table` and validate columns in the body';
  return null;
}

Try / catch

try {
  const sig = parseNuSignature(source);
} catch (e) {
  if (String(e).includes('typed tables are not supported')) {
    throw new Error('Change the annotation to `table` (list of objects) and validate columns inside the script');
  }
  throw e;
}

Prevention

When it happens

Trigger: Declaring `def main [data: table<id: int, name: string>]` — any parameter type containing `table<` — in a Windmill Nushell script.

Common situations: Scripts handling structured tabular data annotated with Nushell's typed tables; migrated internal tooling that relied on table type checking.

Related errors


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