pulumi/pulumi · error · Error
[[Scopes]].value have objectId
Error message
[[Scopes]].value have objectId
What it means
After finding the [[Scopes]] internal property, the serializer requires its value to be a remote object handle with an objectId so it can query the scope chain via the inspector protocol. This error fires when the value exists but carries no objectId, so the scope chain cannot be dereferenced.
Source
Thrown at sdk/nodejs/runtime/closure/v8.ts:102
// First, find the runtime's internal id for this function.
const functionId = await getRuntimeIdForFunctionAsync(func);
// Now, query for the internal properties the runtime sets up for it.
const { internalProperties } = await runtimeGetPropertiesAsync(functionId, /*ownProperties:*/ false);
// There should normally be an internal property called [[Scopes]]:
// https://chromium.googlesource.com/v8/v8.git/+/3f99afc93c9ba1ba5df19f123b93cc3079893c9b/src/inspector/v8-debugger.cc#820
const scopes = internalProperties.find((p) => p.name === "[[Scopes]]");
if (!scopes) {
throw new Error("Could not find [[Scopes]] property");
}
if (!scopes.value) {
throw new Error("[[Scopes]] property did not have [value]");
}
if (!scopes.value.objectId) {
throw new Error("[[Scopes]].value have objectId");
}
// This is sneaky, but we can actually map back from the [[Scopes]] object to a real in-memory
// v8 array-like value. Note: this isn't actually a real array. For example, it cannot be
// iterated. Nor can any actual methods be called on it. However, we can directly index into
// it, and we can. Similarly, the 'object' type it optionally points at is not a true JS
// object. So we can't call things like .hasOwnProperty on it. However, the values pointed to
// by 'object' are the real in-memory JS objects we are looking for. So we can find and return
// those successfully to our caller.
const scopesArray: { object?: Record<string, any> }[] = await getValueForObjectId(scopes.value.objectId);
// scopesArray is ordered from innermost to outermost.
for (let i = 0, n = scopesArray.length; i < n; i++) {
const scope = scopesArray[i];
if (scope.object) {
if (freeVariable in scope.object) {
const val = scope.object[freeVariable];
return val;View on GitHub (pinned to 793f7b2e16)
Solutions
- Pass a plain user-defined function (function declaration/expression or arrow) to serializeFunction — not native, bound, or constructor functions.
- Align Node.js version with the SDK's supported engines; inspector handle semantics changed across V8 releases.
- Check that no runtime proxying/wrapping library replaces your handler with a Proxy or exotic callable before serialization.
- If the issue persists, capture and report the remoteObject JSON from the error to narrow down the V8 behavior.
Example fix
// before
await serializeFunction(Array.prototype.map); // native fn, no real scopes
// after
const fn = () => { /* user code */ };
await serializeFunction(fn); Defensive patterns
Strategy: validation
Validate before calling
function assertInspectableFunction(fn: unknown) {
if (typeof fn !== "function") throw new TypeError("Expected a function");
if (Object.getPrototypeOf(fn) === Function.prototype && fn.toString().includes("[native code]")) {
throw new TypeError("Native/built-in functions have no inspectable scope chain");
}
} Type guard
const isJsFunction = (v: unknown): v is Function =>
typeof v === "function" && !String(v).includes("[native code]"); Try / catch
try { await serializeFunction(fn); } catch (e) { if (/\[\[Scopes\]\]/.test(String(e))) { throw new Error("Function has no inspectable scopes; use a plain JS function.", { cause: e }); } throw e; } Prevention
- Serialize only ordinary JS/TS function expressions or declarations.
- Pin Node to versions listed in the SDK's engines field.
- Strip exotic wrappers (bound, proxied, native) before serializing.
When it happens
Trigger: Runtime.getProperties (v8.ts:102) returns [[Scopes]].value without an objectId — i.e. V8 returned the scopes as a non-object remote value (e.g. type "undefined"/"primitive") instead of a heap object handle, usually when the inspected target lacks a real lexical environment.
Common situations: Serializing built-in/native functions or class constructors without scope objects; inspector responses under mismatched Node/SDK versions; passing a non-function that the protocol still reports as having internal properties.
Related errors
- [[Scopes]] property did not have [value]
- Unexpected missing variable in closure environment: ${freeVa
- Error calling "Runtime.evaluate(${expression})" on context $
- Remote object was not 'function': ${JSON.stringify(remoteObj
- Remote function does not have 'objectId': ${JSON.stringify(r
AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31).
Data as JSON: /api/errors/78455ddd8e4ab5d9.
Report an issue: GitHub.