windmill-labs/windmill · error

fdopen is not supported

Error message

fdopen is not supported

What it means

`fdopen` (associate a stream with an existing file descriptor) is an unimplemented libc stub in the R parser WASM runtime that panics on entry. The sandbox deliberately exposes no file-descriptor/FILE* machinery, so any attempt to open a stream around a fd aborts.

Source

Thrown at backend/parsers/windmill-parser-r/src/wasm_libc.rs:251

#[no_mangle]
pub unsafe extern "C" fn fprintf(_file: *mut c_void, _format: *const c_void, _args: ...) -> c_int {
    panic!("fprintf is not supported");
}

#[no_mangle]
pub unsafe extern "C" fn fputs(_s: *const c_void, _file: *mut c_void) -> c_int {
    panic!("fputs is not supported");
}

#[no_mangle]
pub unsafe extern "C" fn fputc(_c: c_int, _file: *mut c_void) -> c_int {
    panic!("fputc is not supported");
}

#[no_mangle]
pub unsafe extern "C" fn fdopen(_fd: c_int, _mode: *const c_void) -> *mut c_void {
    panic!("fdopen is not supported");
}

#[no_mangle]
pub unsafe extern "C" fn fclose(_file: *mut c_void) -> c_int {
    panic!("fclose is not supported");
}

#[no_mangle]
pub unsafe extern "C" fn fwrite(
    _ptr: *const c_void,
    _size: usize,
    _nmemb: usize,
    _stream: *mut c_void,
) -> usize {
    panic!("fwrite is not supported");
}

#[no_mangle]

View on GitHub (pinned to e474e8803c)

Solutions

  1. Refactor the code to use the parser's supported I/O API instead of fd-based streams
  2. Implement fdopen in wasm_libc.rs if descriptor-backed streams are actually needed (rare; requires full FILE* emulation)
  3. Remove the dependency that requires POSIX file streams
  4. Pre-process R inputs to avoid file-based code paths before parsing/execution

Example fix

// before (stub)
#[no_mangle]
pub unsafe extern "C" fn fdopen(_fd: c_int, _mode: *const c_void) -> *mut c_void {
    panic!("fdopen is not supported");
}
// after (explicit failure instead of panic, if a caller must probe)
#[no_mangle]
pub unsafe extern "C" fn fdopen(_fd: c_int, _mode: *const c_void) -> *mut c_void {
    std::ptr::null_mut() // callers check for NULL and fall back
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check: the sandbox has no file-descriptor support; reject fd/stream-based code paths
if (/\b(fdopen|fileno|open|creat)\s*\(/.test(cOrRSource)) {
  throw new Error("fd-based streams (fdopen) are unsupported in the R parser WASM sandbox");
}

Type guard

fn fdopen_supported(fd_provided: bool) -> bool { !fd_provided } // no fd-backed streams exist; any fd path is unsupported

Try / catch

match std::panic::catch_unwind(|| run_wasm_r(source)) {
    Err(p) if panic_msg(&p).contains("fdopen is not supported") => {
        Err(Error::UnsupportedFileIo("rewrite the code to avoid fdopen; use supported I/O"))
    }
    other => other.map_err(Error::from),
}

Prevention

When it happens

Trigger: Calling the exported `fdopen` shim at backend/parsers/windmill-parser-r/src/wasm_libc.rs:251, e.g. compiled C or R runtime code tries to wrap a raw fd in a FILE* stream.

Common situations: Ported C library code opens streams from descriptors; R code reads/writes files through low-level paths; a dependency expects POSIX file semantics unavailable under WASM.

Related errors


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