Skip to content

Conversation

BridgeAR
Copy link
Member

@BridgeAR BridgeAR commented Aug 11, 2025

Long stack traces often have duplicated stack frames from recursive calls. These make it difficult to identify important parts of the stack. This hides the duplicated ones and notifies the user which lines were hidden.

I believe the wording might still be improved, it would be great to get some input about that.

image

Long stack traces often have duplicated stack frames from recursive
calls. These make it difficult to identify important parts of the
stack. This hides the duplicated ones and notifies the user which
lines were hidden.
@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. util Issues and PRs related to the built-in util module. labels Aug 11, 2025
Copy link

codecov bot commented Aug 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.87%. Comparing base (f993fca) to head (d8a9686).
⚠️ Report is 44 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #59447      +/-   ##
==========================================
- Coverage   89.88%   89.87%   -0.01%     
==========================================
  Files         656      656              
  Lines      192947   193266     +319     
  Branches    37841    37927      +86     
==========================================
+ Hits       173427   173699     +272     
- Misses      12054    12098      +44     
- Partials     7466     7469       +3     
Files with missing lines Coverage Δ
lib/internal/util/inspect.js 99.96% <100.00%> (+0.08%) ⬆️

... and 63 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Member

@legendecas legendecas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be more confusing that a recursive call is not reflected in the stacktrace?

@BridgeAR
Copy link
Member Author

@legendecas it is reflected in form of a comment and the frames are of course kept once. Just the duplicates are removed.
I am often seeing stacks with 100 lines and these are very verbose. This would definitely help to read these stacks :)

@BridgeAR BridgeAR added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. request-ci Add this label to start a Jenkins CI on a PR. labels Aug 12, 2025
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 12, 2025
@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@BridgeAR
Copy link
Member Author

BridgeAR commented Aug 18, 2025

PTAL
I pushed another commit that improves the worst case performance and the algorithm now also matches an additional case. The algorithm became quite a bit more complicated, so this would definitely need another review.

@BridgeAR BridgeAR removed the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Aug 18, 2025
function getDuplicateErrorFrameRanges(frames) {
// Build a map: frame line -> sorted list of indices where it occurs
const result = [];
const lineToPositions = new Map();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are strings, is Map significantly faster than a null object or SafeMap (or even a $-key-salted normal object) such that this is the best choice?

}

// Theoretical maximum range, adjusted while iterating
let range = positions.at(-1) - i;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let range = positions.at(-1) - i;
let range = positions[positions.length - 1] - i;

i assume this is faster, and avoids the need for a primordial

if (gcdRange !== 0) {
// Add other possible ranges as fallback
extraSteps ??= new Set();
extraSteps.add(gcdRange);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similarly, this seems like it could be an object, with ObjectKeys at the end, and it'd be faster than spreading a Set into an array?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be surprised if that's faster, while it will likely not be the major issue (this path is only triggered for some cases and for those, the set / object would contain normally never more than five entries).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's not an issue, can we use SafeMap/SafeSet instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-ci PRs that need a full CI run. util Issues and PRs related to the built-in util module.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants