Skip to content

Smaller API results that are silently wrong: util.inspect(Map/Set), Buffer#indexOf(string), url.pathToFileURL, 'newListener', hash.copy(), ArrayBuffer#transfer #59

Closed

Description

@hassidan

Test I ran

node util_misc.ts
slice run util_misc.ts
util_misc.ts
import * as util from "node:util";
import * as url from "node:url";
import * as crypto from "node:crypto";
import { EventEmitter } from "node:events";
const show = async (k: string, f: () => unknown) => { let v; try { v = await Promise.race([Promise.resolve().then(f), new Promise((r) => setTimeout(() => r("NEVER SETTLED (2000 ms)"), 2000))]); } catch (e: any) { v = "THROWS " + e.name + ": " + String(e.message).slice(0, 100); } console.log(k.padEnd(52) + JSON.stringify(v)); };
(async () => {
  await show("util.inspect(new Map([[1,{a:1}]]))", () => util.inspect(new Map([[1, { a: 1 }]])));
  await show("util.inspect(new Set([1,'a']))", () => util.inspect(new Set([1, "a"])));
  await show("util.format('%o', new Map([[1,2]]))", () => util.format("%s", new Map([[1, 2]])));
  await show("util.inspect(obj, {depth: 0})", () => util.inspect({ a: { b: 1 } }, { depth: 0 }));
  await show("util.inspect deep default depth (2)", () => util.inspect({ a: { b: { c: { d: 1 } } } }));
  await show("util.inspect(new Error('x')) has stack", () => /Error: x\n\s+at /.test(util.inspect(new Error("x"))));
  await show("url.pathToFileURL('/a/b c.txt').href", () => url.pathToFileURL("/a/b c.txt").href);
  await show("EventEmitter 'newListener' event", () => { const e = new EventEmitter(); const o: string[] = []; e.on("newListener", (n) => o.push(String(n))); e.on("z", () => {}); return o; });
  await show("Buffer#indexOf('ca') / includes('b')", () => [Buffer.from("abcabc").indexOf("ca"), Buffer.from("abc").includes("b"), Buffer.from("abc").indexOf(Buffer.from("c")), Buffer.from("abc").indexOf(0x62)]);
  await show("Buffer.from('ab','utf16le').length", () => Buffer.from("ab", "utf16le").length);
  await show("crypto.createHash('sha256').copy()", () => { const h = crypto.createHash("sha256").update("a"); const c = h.copy(); return [h.digest("hex").slice(0, 8), c.update("b").digest("hex").slice(0, 8)]; });
  await show("ArrayBuffer.prototype.transfer", () => { const b = new ArrayBuffer(8); const t = b.transfer(); return [t.byteLength, b.detached]; });
  await show("resizable ArrayBuffer .resize()", () => { const b = new ArrayBuffer(8, { maxByteLength: 16 }); b.resize(12); return b.byteLength; });
})();

Result

Node v24.22.2:

util.inspect(new Map([[1,{a:1}]]))                  "Map(1) { 1 => { a: 1 } }"
util.inspect(new Set([1,'a']))                      "Set(2) { 1, 'a' }"
util.format('%o', new Map([[1,2]]))                 "Map(1) { 1 => 2 }"
util.inspect(obj, {depth: 0})                       "{ a: [Object] }"
util.inspect deep default depth (2)                 "{ a: { b: { c: [Object] } } }"
util.inspect(new Error('x')) has stack              true
url.pathToFileURL('/a/b c.txt').href                "file:///a/b%20c.txt"
EventEmitter 'newListener' event                    ["z"]
Buffer#indexOf('ca') / includes('b')                [2,true,2,1]
Buffer.from('ab','utf16le').length                  4
crypto.createHash('sha256').copy()                  ["ca978112","fb8e20fc"]
ArrayBuffer.prototype.transfer                      [8,true]
resizable ArrayBuffer .resize()                     12

Slice v0.10.7:

util.inspect(new Map([[1,{a:1}]]))                  "{}"
util.inspect(new Set([1,'a']))                      "{}"
util.format('%o', new Map([[1,2]]))                 "[object Map]"
util.inspect(obj, {depth: 0})                       "THROWS TypeError: not a callable function"
util.inspect deep default depth (2)                 "{ a: { b: { c: { d: 1 } } } }"
util.inspect(new Error('x')) has stack              false
url.pathToFileURL('/a/b c.txt').href                "file:///a/b c.txt"
EventEmitter 'newListener' event                    []
Buffer#indexOf('ca') / includes('b')                [-1,false,-1,1]
Buffer.from('ab','utf16le').length                  2
crypto.createHash('sha256').copy()                  "THROWS TypeError: not a callable function"
ArrayBuffer.prototype.transfer                      "THROWS TypeError: not a callable function"
resizable ArrayBuffer .resize()                     12

What is wrong

API Slice Node Listed in COMPATIBILITY.md?
util.inspect(new Map(...)), util.inspect(new Set(...)) {} (contents dropped) Map(1) { 1 => { a: 1 } } util.inspect yes
util.inspect(obj, { depth: 0 }) throws TypeError: not a callable function { a: [Object] } yes
util.inspect default depth nested objects printed past depth 2 stops at depth 2 ([Object]) yes
util.inspect(new Error("x")) no stack message + stack yes
Buffer#indexOf("ca"), #includes("b"), #indexOf(Buffer) -1, false, -1 2, true, 2 no (falls back to Uint8Array#indexOf)
Buffer.from("ab", "utf16le").length 2 4 no
url.pathToFileURL("/a/b c.txt").href file:///a/b c.txt file:///a/b%20c.txt yes
EventEmitter 'newListener' event not emitted emitted "Full EventEmitter class"
crypto.createHash(...).copy() throws works no
ArrayBuffer.prototype.transfer() throws works yes, in §6 ("ArrayBuffer transfer/resize")

Grouped into one issue because each is small. The Buffer#indexOf / #includes rows return a wrong answer instead of throwing, which is why they are here even though the matrix does not claim them.

Environment

  • Slice v0.10.7, commit ea7c70c, built with cargo +1.96.0 build --release --locked --bin slice
  • Reference: Node.js v24.22.2 (same script, same machine)
  • Ubuntu 26.04, Linux 7.0, x86_64
  • The same output is produced by the v0.10.5 tag, so this is not a regression in 0.10.6/0.10.7.

Activity

  1. siktec-lab commented on Nov 11, 2026

    @siktec-lab
    Collaborator

    Addressed in #67 (�0.10.11): implemented util.inspect depth/Map/Set/Error formatting (util.format('%s', map)), Buffer#indexOf/lastIndexOf/includes, url.pathToFileURL percent-encoding (%, #, ?, spaces), EventEmitter 'newListener'/'removeListener' events, crypto.createHash#copy(), and enabled ES2024 ArrayBuffer.prototype.transfer / ransferToFixedLength / detached.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions