{{ message }}
fix(dev-overlay): never let browser log forwarding break console.* - #98288
Open
stop1love1 wants to merge 1 commit into
Open
fix(dev-overlay): never let browser log forwarding break console.*#98288stop1love1 wants to merge 1 commit into
stop1love1 wants to merge 1 commit into
Conversation
`patchConsoleMethod` called the forwarding wrapper before the original console method, with nothing in between. If the wrapper threw, the user's `console.log` both threw back into their code and never reached the real console, so the log was lost precisely when something unusual was being logged. `preLogSerializationClone`, which the wrapper calls, still had two paths that can throw on values the user controls: `Object.getPrototypeOf` (a proxy can trap it) and `Object.prototype.toString`, which reads the `Symbol.toStringTag` getter. Guard both so such values degrade to "[Unable to view]" like the rest of the clone already does, and make the patched method fail-safe so any future gap can't take `console.*` with it. fixes vercel#84864
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What?
Makes browser-to-terminal log forwarding fail-safe so it can never swallow or break a user's
console.*call.Fixes #84864
Why?
patchConsoleMethodruns the forwarding wrapper and then the original console method, with nothing in between:If
wrapperthrows, two things go wrong at once: the exception propagates back into the application code that calledconsole.log(...), andoriginalMethodis never reached — so the log is lost exactly when the user was trying to inspect something unusual. That is the behaviour reported in #84864 ("The original log should be done even if the stringify fails").preLogSerializationCloneis careful about most hostile values — it guardsObject.keys, thethenprobe, array items and property getters — but two paths were still unprotected, and both are reachable from a plainconsole.log(value):Object.getPrototypeOf(value)— aProxycan trapgetPrototypeOfand throw. The earlierObject.keysguard doesn't catch this, becauseownKeyscan succeed whilegetPrototypeOfthrows.Object.prototype.toString.call(value)— this readsSymbol.toStringTag, which is an ordinary getter the value controls, so it can throw too.Since
createLogEntrycallspreLogSerializationCloneoutside anytry, a throw from either line reaches the wrapper and takesconsole.*down with it.Two of the cases originally reported are already handled on
canaryand I did not change them: the vendoredsafe-stable-stringifyserializesBigIntfine (1n→1), andlogStringifyalready catches a throwingtoJSON. What was left is the class of values that breaks the clone before stringification, plus the missing safety net around the wrapper itself.How?
patchConsoleMethod: wrap thewrapper(...)call intry/catchsooriginalMethod.applyalways runs and nothing is thrown back at the caller. The failure is swallowed rather than reported, because reporting it throughconsolewould recurse into this same wrapper — the same reasoning the existingscheduleLogSendflush already uses.preLogSerializationClone: guardObject.getPrototypeOfandObject.prototype.toString.call, returning the existing[Unable to view]marker, consistent with how the function already degrades for throwing getters and unreadable proxies.No behaviour changes for values that serialize normally.
Tests
Three cases added to the existing
packages/next/src/next-devtools/userspace/app/forward-logs.test.ts:getPrototypeOfthrows →[Unable to view]Symbol.toStringTaggetter throws →[Unable to view]patchConsoleMethodwith a throwing wrapper →console.logdoes not throw, and the original method still receives the argumentsAll three fail on
canary(they throwgetPrototypeOf throws/toStringTag throws/wrapper blew up) and pass with this change.Verified locally on Windows:
jest packages/next/src/next-devtools/userspace/app/forward-logs.test.ts— 14/14 pass (11 existing + 3 new)jest packages/next/src/next-devtools/— 214/214 pass across 15 suitespnpm prettier --checkandpnpm lint-eslinton the changed files — cleantest/development/app-dir/browser-log-forwarding/has 2 pre-existing failures on this machine (warn-level,verbose-level): their inline snapshots expectapp/page.tsxbut Windows producesapp\page.tsx. I confirmed both fail identically on unmodifiedcanary, so they are unrelated to this change and I have not touched them.