Summary
Node path.relative(from, to) requires both arguments to be strings and throws TypeError ERR_INVALID_ARG_TYPE when either argument is not a string. Perry's dynamic native dispatch validates those arguments, but the compiled fast path lowers path.relative() directly to runtime helpers that silently treat invalid string pointers as empty strings.
Node 25.9.0 behavior
const path = require("node:path");
for (const args of [[1, "x"], ["x", 1], [null, "x"], ["x", undefined]]) {
try { path.relative(...args); }
catch (err) { console.log(err.name, err.code); }
}
// TypeError ERR_INVALID_ARG_TYPE for every case
The same validation applies to path.posix.relative() and path.win32.relative().
Perry source evidence
crates/perry-runtime/src/object/native_module_dispatch.rs uses require_path_str_ptr(0) / require_path_str_ptr(1) for dynamic path.posix.relative and path.win32.relative, so that path is guarded.
crates/perry-hir/src/lower/expr_call/module_static.rs, globals.rs, and nested_namespace.rs lower recognized path.relative(...) calls with two arguments to Expr::PathRelative / win32 method expressions without adding argument validation.
crates/perry-codegen/src/expr/instance_misc1.rs lowers Expr::PathRelative by unboxing both operands and calling js_path_relative(from, to) directly.
crates/perry-runtime/src/path.rs::js_path_relative() reads both inputs with string_from_header(...).unwrap_or_default(); js_path_win32_relative() does the same. Invalid/non-string operands therefore become "" instead of throwing.
Expected
All lowering paths for path.relative(), path.posix.relative(), and path.win32.relative() should perform the same string validation as dynamic dispatch and throw TypeError ERR_INVALID_ARG_TYPE for either non-string argument.
Duplicate checks
path.relative non-string type error
PathRelative js_path_relative non-string
- PR search for
path.relative type
I did not find an existing issue for the compiled path.relative() validation path.
Summary
Node
path.relative(from, to)requires both arguments to be strings and throwsTypeError ERR_INVALID_ARG_TYPEwhen either argument is not a string. Perry's dynamic native dispatch validates those arguments, but the compiled fast path lowerspath.relative()directly to runtime helpers that silently treat invalid string pointers as empty strings.Node 25.9.0 behavior
The same validation applies to
path.posix.relative()andpath.win32.relative().Perry source evidence
crates/perry-runtime/src/object/native_module_dispatch.rsusesrequire_path_str_ptr(0)/require_path_str_ptr(1)for dynamicpath.posix.relativeandpath.win32.relative, so that path is guarded.crates/perry-hir/src/lower/expr_call/module_static.rs,globals.rs, andnested_namespace.rslower recognizedpath.relative(...)calls with two arguments toExpr::PathRelative/ win32 method expressions without adding argument validation.crates/perry-codegen/src/expr/instance_misc1.rslowersExpr::PathRelativeby unboxing both operands and callingjs_path_relative(from, to)directly.crates/perry-runtime/src/path.rs::js_path_relative()reads both inputs withstring_from_header(...).unwrap_or_default();js_path_win32_relative()does the same. Invalid/non-string operands therefore become""instead of throwing.Expected
All lowering paths for
path.relative(),path.posix.relative(), andpath.win32.relative()should perform the same string validation as dynamic dispatch and throwTypeError ERR_INVALID_ARG_TYPEfor either non-string argument.Duplicate checks
path.relative non-string type errorPathRelative js_path_relative non-stringpath.relative typeI did not find an existing issue for the compiled
path.relative()validation path.