windmill-labs/windmill · error

snprintf is not supported

Error message

snprintf is not supported

What it means

The windmill-parser-java WASM module (a tree-sitter Java parser compiled to wasm32) ships a hand-written libc shim in wasm_libc.rs. snprintf is deliberately stubbed to panic! because the in-WASM C code has no stdio; the stub exists only so the module links. When the parser's C code calls snprintf at runtime, the stub panics with "snprintf is not supported", aborting the parse.

Source

Thrown at backend/parsers/windmill-parser-java/src/wasm_libc.rs:201

#[no_mangle]
pub unsafe extern "C" fn vsnprintf(
    _buf: *mut c_char,
    _size: usize,
    _format: *const c_char,
    _args: ...
) -> c_int {
    panic!("vsnprintf is not supported");
}

#[no_mangle]
pub extern "C" fn clock_gettime(ptr: usize, new_size: usize) {
    panic!("clock_gettime is not supported");
}

// int snprintf( char* restrict buffer, size_t bufsz, const char* restrict format, ... );
#[no_mangle]
pub extern "C" fn snprintf() {
    panic!("snprintf is not supported");
}

#[no_mangle]
pub extern "C" fn __assert_fail(_: *const i32, _: *const i32, _: *const i32, _: *const i32) {
    panic!("oh no");
}

View on GitHub (pinned to e474e8803c)

Solutions

  1. Implement snprintf in wasm_libc.rs instead of panicking — parse the format string minimally (or return the number of chars that would be written and leave the buffer untouched) so the caller proceeds.
  2. Check the tree-sitter-java version and downgrade to one whose generated C/scanner does not call snprintf.
  3. If you control the grammar, patch scanner.c to avoid snprintf (e.g. copy strings directly with memcpy/strcpy, which the shim supports or can trivially implement).
  4. Report the grammar/scanner combination upstream so the Windmill parser WASM build gets a working shim implementation.

Example fix

// before (wasm_libc.rs)
#[no_mangle]
pub extern "C" fn snprintf() {
    panic!("snprintf is not supported");
}

// after — minimal no-op that lets callers continue
#[no_mangle]
pub unsafe extern "C" fn snprintf(
    buf: *mut c_char,
    _bufsz: usize,
    _format: *const c_char,
    _args: ...
) -> c_int {
    if !buf.is_null() {
        *buf = 0; // empty string
    }
    0
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Nothing caller-side can pre-check the C internals, but you can isolate the blast radius:
// parse untrusted documents in a fresh parser instance / worker so a panic
does not poison subsequent parses.
function safeParse(parser, doc) {
  if (typeof doc !== 'string' || doc.length === 0) return null; // skip empty/invalid input
  return doc; // proceed, but expect the call below to throw on snprintf paths
}

Type guard

function isParsableInput(doc) {
  return typeof doc === 'string' && doc.length > 0;
}

Try / catch

let tree;
try {
  tree = parser.parse(doc);
} catch (e) {
  if (String(e).includes('snprintf is not supported')) {
    // grammar's scanner needs an unsupported libc symbol: recreate parser
    parser = new Parser(); // discard possibly-corrupted state
    // fall back to a different parser version or mark doc unparseable
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: The compiled tree-sitter scanner/parser code calls snprintf() at runtime — typically from a custom scanner.c that formats diagnostic strings or token text. Any grammar whose C runtime or scanner invokes snprintf triggers this stub immediately.

Common situations: Parsing a Java source file whose tree-sitter-java scanner path calls snprintf; running the parser inside the WASM sandbox (no real libc); upgrading tree-sitter or the grammar to a version whose generated C uses snprintf when the older version did not.

Related errors


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