denoland/deno · error · Error

${name} is already registered

Error message

${name} is already registered

What it means

Deno.core.registerTransferableResource(name, send, receive) installs the serializer/deserializer pair used when a resource of that kind crosses a worker postMessage boundary. Names key a single global registry in 01_core.js and must be unique; registering an existing name throws `Error: ${name} is already registered` because structured clone could not decide which receive function to trust. This is an internal API used when building extensions or custom runtime snapshots.

Source

Thrown at libs/core/01_core.js:727

    op_shutdown: shutdown,
    op_is_terminal: isTerminal,
  } = ops;

  const callSiteRetBuf = new Uint32Array(2);
  const callSiteRetBufU8 = new Uint8Array(callSiteRetBuf.buffer);

  function currentUserCallSite() {
    const fileName = op_current_user_call_site(callSiteRetBufU8);
    const lineNumber = callSiteRetBuf[0];
    const columnNumber = callSiteRetBuf[1];
    return { fileName, lineNumber, columnNumber };
  }

  const hostObjectBrand = SymbolFor("Deno.core.hostObject");
  const transferableResources = {};
  const registerTransferableResource = (name, send, receive) => {
    if (transferableResources[name]) {
      throw new Error(`${name} is already registered`);
    }
    transferableResources[name] = { send, receive };
  };
  const getTransferableResource = (name) => transferableResources[name];
  const cloneableDeserializers = { __proto__: null };
  const registerCloneableResource = (name, deserialize) => {
    if (cloneableDeserializers[name]) {
      throw new Error(`${name} is already registered`);
    }
    cloneableDeserializers[name] = deserialize;
  };
  const getCloneableDeserializers = () => cloneableDeserializers;

  // A helper function that will bind our own console implementation
  // with default implementation of Console from V8. This will cause
  // console messages to be piped to inspector console.
  //
  // We are using `Deno.core.callConsole` binding to preserve proper stack

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Give each registration a unique, namespaced name such as 'myExt.myResource'
  2. Check `core.getTransferableResource(name)` is undefined first, and skip or fail with a clearer diagnostic
  3. Make the extension's init script idempotent and ensure it loads exactly once (deduplicate the extension list)

Example fix

// before
core.registerTransferableResource('blob', send, receive); // second registration of 'blob' throws

// after
if (core.getTransferableResource('myExt.blob') === undefined) {
  core.registerTransferableResource('myExt.blob', send, receive);
}
Defensive patterns

Strategy: validation

Validate before calling

if (core.getTransferableResource(name) !== undefined) {
  throw new Error(`transferable resource '${name}' is already registered`);
}
core.registerTransferableResource(name, send, receive);

Prevention

When it happens

Trigger: Two extensions registering a transferable resource under the same name during snapshot bootstrap; an extension's init JavaScript being evaluated twice; a forked/copied extension keeping the original resource name.

Common situations: Building custom runtimes with deno_core's ExtensionBuilder JS snippets; name collisions between first-party and third-party extensions (e.g. two variants both registering a body/file resource); duplicate bootstrap in tests.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/52346bee64ce4e86. Report an issue: GitHub.