Skip to content

fix(util): render [Object: null prototype] prefix in util.inspect (Node parity)#5107

Merged
proggeramlug merged 2 commits into
mainfrom
fix/inspect-null-proto-prefix
Jun 14, 2026
Merged

fix(util): render [Object: null prototype] prefix in util.inspect (Node parity)#5107
proggeramlug merged 2 commits into
mainfrom
fix/inspect-null-proto-prefix

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Problem

util.inspect / console.log of a null-prototype object printed it as a bare {}, where Node prefixes it with [Object: null prototype]:

                            # node v26.3.0                  # perry (before)
util.inspect(Object.create(null)) → [Object: null prototype] {}   →  {}

These objects are common as option bags / lookup maps, so the missing prefix is a visible parity gap.

Fix

Detect the existing OBJ_FLAG_NULL_PROTO GC-header flag (set by js_object_alloc_null_proto) in the object formatter and introduce a name_prefix that resolves to:

  • the constructor/class name when present,
  • else [Object: null prototype] for a null-proto plain object,
  • else nothing.

name_prefix replaces class_name_ref only at the three render sites (empty / single-line / multi-line). has_class_name (which drives the #private-field skip) still reflects a genuine class, so behavior for normal and class objects is unchanged.

Verification (vs Node v26.3.0)

  • Object.create(null)[Object: null prototype] {}
  • All 17 other inspect-probe cases unchanged (classes Foo { x: 1 }, Map(1) { … }, Set, circular <ref *1>, Error, Date, RegExp, [Getter], bigint, NaN/Infinity, …).
  • perry-runtime formatting + inspect unit tests pass (12).

Found via a util.inspect differential sweep vs Node; relates to the console/util-formatting parity gap in CLAUDE.md and the parity roadmap (#4315). (Known remaining inspect nits, left out of scope: sparse-array holes render as NaN not <1 empty item>, and Node's quote-style heuristic / showHidden array [length].)

No version bump / changelog per maintainer instruction.

Summary by CodeRabbit

  • Bug Fixes
    • Improved formatting for null-prototype plain objects so they consistently display as [Object: null prototype] across both compact and expanded output views.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fea67c9a-e438-437a-ba93-8826ef2bcbf6

📥 Commits

Reviewing files that changed from the base of the PR and between 90a8a53 and 6023e60.

📒 Files selected for processing (1)
  • crates/perry-runtime/src/builtins/formatting.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/perry-runtime/src/builtins/formatting.rs

📝 Walkthrough

Walkthrough

format_object_as_json now reads the OBJ_FLAG_NULL_PROTO bit from the object's GcHeader reserved flags to compute a name_prefix. When no boxed_base is present and the object is null-proto, name_prefix becomes [Object: null prototype]. The empty-object closure and both the single-line and multi-line wrapper-selection match arms are updated to use name_prefix instead of class_name_ref.

Changes

Null-prototype object prefix rendering

Layer / File(s) Summary
Null-prototype detection and prefix propagation
crates/perry-runtime/src/builtins/formatting.rs
Reads OBJ_FLAG_NULL_PROTO from GcHeader reserved flags to produce name_prefix; updates the empty_object closure and both the single-line and multi-line wrapper-selection branches to switch on (boxed_base, name_prefix) instead of (boxed_base, class_name_ref).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 A rabbit hops past a proto-less door,
No ancestor found on the prototype floor.
The header bit flips, the prefix shines bright:
[Object: null prototype] — displayed just right!
With single and multi-line wrapped up with care,
The null-proto object is finally there. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: fixing null-prototype object formatting in util.inspect to match Node.js behavior.
Description check ✅ Passed The description comprehensively covers the problem, solution, and verification, following most template sections. However, the Test plan checkbox section is not explicitly marked as completed.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/inspect-null-proto-prefix

Comment @coderabbitai help to get the list of available commands and usage tips.

@proggeramlug proggeramlug force-pushed the fix/inspect-null-proto-prefix branch from a94f8ce to dd43d5b Compare June 14, 2026 05:12
@proggeramlug proggeramlug force-pushed the fix/inspect-null-proto-prefix branch from dd43d5b to 90a8a53 Compare June 14, 2026 06:06
Ralph Küpper added 2 commits June 14, 2026 09:33
…de parity)

`util.inspect` / `console.log` of a null-prototype object (e.g.
`Object.create(null)`) printed it as a bare `{}` / `{ a: 1 }`, where Node
prefixes it with `[Object: null prototype]` (it has no constructor to
name). These objects are common as option bags / lookup maps, so the
missing prefix is a visible parity gap.

Detect the existing `OBJ_FLAG_NULL_PROTO` GC-header flag (set by
`js_object_alloc_null_proto`) in the object formatter and introduce a
`name_prefix` that resolves to the constructor/class name when present,
else `[Object: null prototype]` for a null-proto plain object, else
nothing. `name_prefix` replaces `class_name_ref` only at the three
render sites (empty / single-line / multi-line); `has_class_name`
(private-field skip) still reflects a genuine class.

Verified vs Node v26.3.0: `Object.create(null)` → `[Object: null
prototype] {}`; all 17 other inspect probe cases (classes, Map/Set,
circular, Error, Date, RegExp, getters, bigint, …) unchanged.
formatting/inspect unit tests pass (12).
@proggeramlug proggeramlug force-pushed the fix/inspect-null-proto-prefix branch from 90a8a53 to 6023e60 Compare June 14, 2026 07:33
@proggeramlug proggeramlug merged commit 13c8e05 into main Jun 14, 2026
15 checks passed
@proggeramlug proggeramlug deleted the fix/inspect-null-proto-prefix branch June 14, 2026 08:46
proggeramlug pushed a commit that referenced this pull request Jun 14, 2026
Rolls up the issue-fix batch merged on top of 0.5.1165 (#5102, #5103,
#5105, #5106, #5107, #5108, #5109, #5110, #5112, #5117). See CHANGELOG
for the per-PR breakdown.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant