Skip to content

node:process: match loadEnvFile path argument handling #3045

@andrewtdiz

Description

@andrewtdiz

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions