Description
Version
v16.13.1
Platform
Darwin MacBook-Pro 21.3.0 Darwin Kernel Version 21.3.0: Wed Jan 5 21:37:58 PST 2022; root:xnu-8019.80.24~20/RELEASE_ARM64_T6000 arm64
Subsystem
No response
What steps will reproduce the bug?
Type the following interactively at the Node shell.
~$ node
Welcome to Node.js v16.13.1.
Type ".help" for more information.
> const p = Promise.resolve(8);
undefined
> const names = Reflect.ownKeys(p);
undefined
> names
[
'domain',
Symbol(async_id_symbol),
Symbol(trigger_async_id_symbol),
Symbol(destroyed)
]
> for (const name of names) {
... delete p[name];
... }
true
> Object.freeze(p);
Promise { 8 }
> const q = p.then(x => console.log(x));
Uncaught:
TypeError: Cannot add property Symbol(async_id_symbol), object is not extensible
at getOrSetAsyncId (node:internal/async_hooks:424:34)
at trackPromise (node:internal/async_hooks:314:35)
at promiseInitHook (node:internal/async_hooks:322:3)
at promiseInitHookWithDestroyTracking (node:internal/async_hooks:329:3)
at Promise.then (<anonymous>)
> undefined
> 8
The 'domain' property is not the main concern here. Rather it is the other three symbols. Hardened JS (aka SES) avoid loading the module that would add 'domain'. However, at the vscode debug terminal, we get a result much like the above but without 'domain' showing up in the list of names. Other differences between the following and the previous section are probably due to the differences caused by Hardened JS and might or might now be relevant. Other than the expected absence of 'domain', the underlying Node bug is the same:
In the debug console:
p = Promise.resolve(8);
Promise {[[PromiseState]]: 'fulfilled', [[PromiseResult]]: 8, Symbol(async_id_symbol): 3543, Symbol(trigger_async_id_symbol): 1783, Symbol(destroyed): {…}}
names = Reflect.ownKeys(p);
(3) [Symbol(async_id_symbol), Symbol(trigger_async_id_symbol), Symbol(destroyed)]
for (const name of names) {
delete p[name];
}
true
Object.freeze(p);
Promise {[[PromiseState]]: 'fulfilled', [[PromiseResult]]: 8}
q = p.then(x => console.log(x));
That last line will terminate the debug session, with the following error appearing on vscode's JavaScript Debug Terminal
Debugger attached.
- range queries
Uncaught exception in test/test-rankOrder.js
TypeError: Cannot add property Symbol(async_id_symbol), object is not extensible
at Promise.then (<anonymous>)
at eval (eval at <anonymous> (packages/store/test/test-rankOrder.js:94:7), <anonymous>:1:13)
at packages/store/test/test-rankOrder.js:94:7
at packages/store/test/test-rankOrder.js:90:12
at async Promise.all (index 7)
› Promise.then (<anonymous>)
› eval (eval at <anonymous> (packages/store/test/test-rankOrder.js:94:7), <anonymous>:1:13)
› packages/store/test/test-rankOrder.js:94:7
› packages/store/test/test-rankOrder.js:90:12
(TypeError#1)
Waiting for the debugger to disconnect...
TypeError#1: Cannot add property Symbol(async_id_symbol), object is not extensible
at Promise.then (<anonymous>)
at eval (eval at <anonymous> (packages/store/test/test-rankOrder.js:94:7), <anonymous>:1:13)
at packages/store/test/test-rankOrder.js:94:7
at packages/store/test/test-rankOrder.js:90:12
at async Promise.all (index 7)
✖ test/test-rankOrder.js exited with a non-zero exit code: 1
─
1 test skipped
1 uncaught exception
Waiting for the debugger to disconnect...
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Waiting for the debugger to disconnect...
Waiting for the debugger to disconnect...
Putting the same code in a .js file and executing it non-interactively does not trigger the bug. The names
array in that case is empty, as it should be.
How often does it reproduce? Is there a required condition?
It reproduces reliably. The explanation above should be adequate to reliably reproduce it. Please let me know if you have any trouble reproducing it.
What is the expected behavior?
names
should be empty.
q
should be defined as a promise that eventually fulfills to p's fulfillment, 8.
What do you see instead?
As presented above:
~$ node
Welcome to Node.js v16.13.1.
Type ".help" for more information.
> const p = Promise.resolve(8);
undefined
> const names = Reflect.ownKeys(p);
undefined
> names
[
'domain',
Symbol(async_id_symbol),
Symbol(trigger_async_id_symbol),
Symbol(destroyed)
]
> for (const name of names) {
... delete p[name];
... }
true
> Object.freeze(p);
Promise { 8 }
> const q = p.then(x => console.log(x));
Uncaught:
TypeError: Cannot add property Symbol(async_id_symbol), object is not extensible
at getOrSetAsyncId (node:internal/async_hooks:424:34)
at trackPromise (node:internal/async_hooks:314:35)
at promiseInitHook (node:internal/async_hooks:322:3)
at promiseInitHookWithDestroyTracking (node:internal/async_hooks:329:3)
at Promise.then (<anonymous>)
> undefined
> 8
Additional information
Googling led me to
https://stackoverflow.com/questions/70742387/where-can-i-find-any-docs-on-why-node-14-changed-promise-into-promise-undefi
which led me to
f37c26b
and
#36394
However, that PR shows Closed rather than Merged, so it may not actually be the source of the bug.