Skip to content

AsyncResource behaves differently w/ AsyncLocalStorage in v24.0.0 #58204

Open
@bengl

Description

@bengl

Version

v24.0.0

Platform

Darwin [computer name] 24.4.0 Darwin Kernel Version 24.4.0: Fri Apr 11 18:33:47 PDT 2025; root:xnu-11417.101.15~117/RELEASE_ARM64_T6000 arm64 arm Darwin

Subsystem

async_hooks

What steps will reproduce the bug?

const { AsyncLocalStorage, AsyncResource } = require('async_hooks')
const { strictEqual } = require('assert')

const storage = new AsyncLocalStorage()

storage.enterWith(1)
const ar = new AsyncResource('test')
ar.runInAsyncScope(() => {
  storage.enterWith(2)
  ar.runInAsyncScope(() => strictEqual(storage.getStore(), 2))
})

Running this in Node.js 24.0.0 breaks, and it passes on all earlier versions.

How often does it reproduce? Is there a required condition?

This is reproducible as long as --no-async-context-frame is not set.

What is the expected behavior? Why is that the expected behavior?

This should pass, as it does on previous versions. If a storage is entered with a given store in a runAsyncContext() block of an AsyncResource, then future invocations of getStore() should return store as long as no other enterWith() has been called on that storage.

What do you see instead?

node:assert:95
  throw new AssertionError(obj);
  ^

AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

1 !== 2

    at /path/to/broken-async.js:10:28
    at AsyncResource.runInAsyncScope (node:async_hooks:214:14)
    at /path/to/broken-async.js:10:6
    at AsyncResource.runInAsyncScope (node:async_hooks:214:14)
    at Object.<anonymous> (/path/to/broken-async.js:8:4)
    at Module._compile (node:internal/modules/cjs/loader:1734:14)
    at Object..js (node:internal/modules/cjs/loader:1899:10)
    at Module.load (node:internal/modules/cjs/loader:1469:32)
    at Module._load (node:internal/modules/cjs/loader:1286:12)
    at TracingChannel.traceSync (node:diagnostics_channel:322:14) {
  generatedMessage: true,
  code: 'ERR_ASSERTION',
  actual: 1,
  expected: 2,
  operator: 'strictEqual'
}

Node.js v24.0.0

It looks like it's reverting to the store that was active when the AsyncResource was created.

Additional information

The test case provided is a whittled-down version of something we do in legacy instrumentations in dd-trace-js that pre-date tracingChannel. Re-implementing those instrumentations using tracingChannel solves this, since we're then not doing anything too strange with AsyncResources like we are here.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions