{"record":{"id":"8aed6344b453f44e","repo":"denoland/deno","slug":"err-vm-module-already-linked","errorCode":"ERR_VM_MODULE_ALREADY_LINKED","errorMessage":"Module has already been linked","messagePattern":"Module has already been linked","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/vm.js","lineNumber":625,"sourceCode":"    if (this[kLinkingStatus] !== null) {\n      return this[kLinkingStatus];\n    }\n    return STATUS_NAMES[op_vm_module_get_status(this[kWrap])];\n  }\n\n  get error() {\n    if (this.status !== \"errored\") {\n      throw new ERR_VM_MODULE_STATUS(\"must be errored\");\n    }\n    return op_vm_module_get_exception(this[kWrap]);\n  }\n\n  link(linker) {\n    if (typeof linker !== \"function\") {\n      throw new ERR_INVALID_ARG_TYPE(\"linker\", \"function\", linker);\n    }\n    if (this.status !== \"unlinked\") {\n      throw new ERR_VM_MODULE_ALREADY_LINKED();\n    }\n    this[kLinkingStatus] = \"linking\";\n    return PromisePrototypeThen(this[kLink](linker), (v) => {\n      this[kLinkingStatus] = null;\n      return v;\n    }, (e) => {\n      this[kLinkingStatus] = null;\n      throw e;\n    });\n  }\n\n  // Two-phase linking so cyclic imports are supported. First walk the whole\n  // dependency graph, calling the linker for each module and recording its\n  // resolved dependencies via `op_vm_module_link`, WITHOUT instantiating.\n  // Then instantiate once at the root - V8 instantiates the entire graph in\n  // a single pass. Decoupling linking from instantiation is what lets a\n  // module that (transitively) imports itself resolve: the `visited` set\n  // short-circuits the cycle once a module has recorded its resolutions.","sourceCodeStart":607,"sourceCodeEnd":643,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/vm.js#L607-L643","documentation":"Module#link(linker) can run only once per module: it throws ERR_VM_MODULE_ALREADY_LINKED whenever status is anything other than 'unlinked' — including while a link is in flight ('linking') or after it completed. Re-linking a cached or shared module is the usual cause.","triggerScenarios":"Calling m.link() twice; concurrent link() calls on the same module; a linker cache that returns an already-linked dependency which then gets linked again from a new entry point.","commonSituations":"Caching modules for repeated runs (hot reload, replays) but re-linking each run; parallel paths (Promise.all) both linking a shared dependency; retry wrappers that re-run link after an unrelated failure.","solutions":["Check status first: if (m.status === 'unlinked') await m.link(linker).","Cache linked modules and reuse them — link once, then evaluate/use as needed.","Serialize linking with a per-module memoized promise so concurrent callers await the same operation."],"exampleFix":"// before\nfor (const run of runs) {\n  await m.link(linker); // second iteration throws ERR_VM_MODULE_ALREADY_LINKED\n  await m.evaluate();\n}\n\n// after\nif (m.status === \"unlinked\") await m.link(linker);\nawait m.evaluate();\nfor (const run of runs) use(m.namespace);","handlingStrategy":"validation","validationCode":"const linkStates = new WeakMap();\nasync function linkOnce(m, linker) {\n  if (!linkStates.has(m)) {\n    linkStates.set(m, m.link(linker));\n  }\n  await linkStates.get(m);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await m.link(linker);\n} catch (err) {\n  if (err.code === \"ERR_VM_MODULE_ALREADY_LINKED\") return; // idempotent\n  throw err;\n}","preventionTips":["Route every link through one linkOnce helper.","Never assume a fresh module per request unless you construct one; cached modules carry their link state.","A link still in flight also blocks a second link — await the first promise, don't re-issue."],"tags":["vm","module-lifecycle","err-vm-module-already-linked","linking"],"backgroundTag":"vm-module-lifecycle","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}