Summary
process.loadEnvFile(path?) should use Node-compatible path argument semantics. Node treats omitted, undefined, and null as the default .env path, accepts string, Buffer, and file: URL paths, and rejects other values with ERR_INVALID_ARG_TYPE. Perry currently routes the call through an optional string pointer, so it cannot accept Buffer/URL paths and does not preserve the same nullish/default and invalid-type behavior.
Node.js behavior
Observed locally with Node v25.9.0:
const fs = require("fs");
const os = require("os");
const path = require("path");
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "loadenv-probe-"));
const file = path.join(tmp, ".env");
fs.writeFileSync(file, "PERRY_LOADENV_PROBE=ok\n");
for (const [label, value] of [
["number", 123],
["object", {}],
["array", []],
["boolean", true],
["symbol", Symbol("x")],
["buffer", Buffer.from(file)],
["url", new URL("file://" + file)],
["string", file],
]) {
try {
delete process.env.PERRY_LOADENV_PROBE;
const result = process.loadEnvFile(value);
console.log(label, "OK", result, process.env.PERRY_LOADENV_PROBE || "unset");
} catch (err) {
console.log(label, "THROW", err.name, err.code, err.message.split("\n")[0]);
}
}
Output:
number THROW TypeError ERR_INVALID_ARG_TYPE The "path" argument must be of type string or an instance of Buffer or URL. Received type number (123)
object THROW TypeError ERR_INVALID_ARG_TYPE The "path" argument must be of type string or an instance of Buffer or URL. Received an instance of Object
array THROW TypeError ERR_INVALID_ARG_TYPE The "path" argument must be of type string or an instance of Buffer or URL. Received an instance of Array
boolean THROW TypeError ERR_INVALID_ARG_TYPE The "path" argument must be of type string or an instance of Buffer or URL. Received type boolean (true)
symbol THROW TypeError ERR_INVALID_ARG_TYPE The "path" argument must be of type string or an instance of Buffer or URL. Received type symbol (Symbol(x))
buffer OK undefined ok
url OK undefined ok
string OK undefined ok
A second probe from a temporary directory containing .env shows omitted, explicit undefined, and explicit null all load the default file and return undefined on success.
Current Perry behavior
crates/perry-runtime/src/object/native_module_dispatch.rs routes ("process", "loadEnvFile") to crate::process::js_process_load_env_file(optional_path_str_ptr(0)).
optional_path_str_ptr() only returns null for omitted/undefined, materializes heap strings, and otherwise throws the generic invalid path argument error; explicit null is rejected instead of using the default .env path.
crates/perry-runtime/src/process.rs::js_process_load_env_file() accepts only *const StringHeader or null, so Buffer and URL path values have no supported path through the runtime helper.
Suggested test surface
process.loadEnvFile() / process.loadEnvFile(undefined) / process.loadEnvFile(null) all use .env in the current directory.
- String, Buffer, and
file: URL paths load the target file and return undefined.
- Number, boolean, object, array, symbol, and unsupported URL values throw Node-compatible
ERR_INVALID_ARG_TYPE errors before trying to open .env.
Duplicate checks
Searched issues for loadEnvFile path validation, process.loadEnvFile Buffer URL path, and loadEnvFile invalid path; searched PRs for loadEnvFile path validation OR loadEnvFile Buffer URL. I only found the implementation work (#1399 / PRs #1505, #1515, #2286) and the open dotenv syntax issue (#2985), which is a separate parser-semantics gap.
Summary
process.loadEnvFile(path?)should use Node-compatible path argument semantics. Node treats omitted,undefined, andnullas the default.envpath, accepts string,Buffer, andfile:URL paths, and rejects other values withERR_INVALID_ARG_TYPE. Perry currently routes the call through an optional string pointer, so it cannot accept Buffer/URL paths and does not preserve the same nullish/default and invalid-type behavior.Node.js behavior
Observed locally with Node v25.9.0:
Output:
A second probe from a temporary directory containing
.envshows omitted, explicitundefined, and explicitnullall load the default file and returnundefinedon success.Current Perry behavior
crates/perry-runtime/src/object/native_module_dispatch.rsroutes("process", "loadEnvFile")tocrate::process::js_process_load_env_file(optional_path_str_ptr(0)).optional_path_str_ptr()only returns null for omitted/undefined, materializes heap strings, and otherwise throws the generic invalid path argument error; explicitnullis rejected instead of using the default.envpath.crates/perry-runtime/src/process.rs::js_process_load_env_file()accepts only*const StringHeaderor null, so Buffer and URL path values have no supported path through the runtime helper.Suggested test surface
process.loadEnvFile()/process.loadEnvFile(undefined)/process.loadEnvFile(null)all use.envin the current directory.file:URL paths load the target file and returnundefined.ERR_INVALID_ARG_TYPEerrors before trying to open.env.Duplicate checks
Searched issues for
loadEnvFile path validation,process.loadEnvFile Buffer URL path, andloadEnvFile invalid path; searched PRs forloadEnvFile path validation OR loadEnvFile Buffer URL. I only found the implementation work (#1399 / PRs #1505, #1515, #2286) and the open dotenv syntax issue (#2985), which is a separate parser-semantics gap.