windmill-labs/windmill · error
fclose is not supported
Error message
fclose is not supported
What it means
`fclose` (close a FILE* stream) is a panicking stub in the R parser's WASM libc shim layer. Since no stream can be opened in the first place (fopen/fdopen are unsupported), reaching fclose means code is unconditionally running a stdio lifecycle the sandbox never implemented.
Source
Thrown at backend/parsers/windmill-parser-r/src/wasm_libc.rs:256
#[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]
pub unsafe extern "C" fn vsnprintf(
_buf: *mut c_char,
_size: usize,
_format: *const c_char,
_args: ...View on GitHub (pinned to e474e8803c)
Solutions
- Remove/guard the stream-cleanup code path since no real streams exist in the WASM sandbox
- Implement fclose as a no-op returning 0 if linked code unconditionally calls it
- Rewrite the R/C code to avoid FILE* connections, using supported input/output mechanisms
- Track as an unsupported-symbol gap and emulate a minimal stream lifecycle if needed
Example fix
// before (stub)
#[no_mangle]
pub unsafe extern "C" fn fclose(_file: *mut c_void) -> c_int {
panic!("fclose is not supported");
}
// after (safe no-op for unreachable streams)
#[no_mangle]
pub unsafe extern "C" fn fclose(_file: *mut c_void) -> c_int {
0 // no real streams exist in WASM; succeed harmlessly
} Defensive patterns
Strategy: try-catch
Validate before calling
// If no stream can be opened, fclose can never be legitimate: flag stream lifecycle code
if (/\b(fopen|fdopen|fclose)\s*\(/.test(source)) {
console.warn("source uses FILE* lifecycle APIs unsupported by the R parser WASM");
} Type guard
// Rust: FILE* handles from this sandbox are always null/invalid
fn stream_valid(file: *mut c_void) -> bool { !file.is_null() } // always false here; any close path is dead code Try / catch
let res = std::panic::catch_unwind(AssertUnwindSafe(|| run_wasm_r(source)));
match res {
Ok(v) => v,
Err(p) if panic_msg(&p).contains("fclose is not supported") => {
// strip or stub the stream-cleanup path in the source and retry once
retry_without_stream_teardown(source)
}
Err(p) => std::panic::resume_unwind(p),
} Prevention
- Remove stream open/close lifecycle code from payloads intended for the WASM parser
- Treat any FILE* value in this sandbox as invalid — never call closers on it
- If linked C code always calls fclose, provide a no-op shim rather than a panic
- Cover teardown paths in tests; they often run only on error exits
When it happens
Trigger: Calling the exported `fclose` shim at backend/parsers/windmill-parser-r/src/wasm_libc.rs:256, typically cleanup code in compiled C/R runtime that closes streams on exit or error paths.
Common situations: Library teardown code always calls fclose; R script uses file connections that compile to stdio calls; a dependency's destructor flushes and closes streams.
Related errors
- fdopen is not supported
- fwrite is not supported
- fdopen is not supported
- fclose is not supported
- fdopen is not supported
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/234c34e1f2d31e30.
Report an issue: GitHub.