markedjs/marked · error · Error

extension name required

Error message

extension name required

What it means

Thrown by Marked.use() (and the Marked constructor, which calls use) when an entry in the extensions array has no name property. Every extension must declare a non-empty name string that identifies the token type it produces and/or renders (MarkedOptions.ts:16-22, 30-33). The name doubles as the key under which a renderer is stored and the token type the parser dispatches on, so a missing or empty name makes registration ambiguous and is rejected before any markdown is parsed. This is a synchronous, configuration-time error.

Source

Thrown at src/Instance.ts:112

   * behavior and extensions registered by earlier calls.
   *
   * Use this method when supplying only some hook methods.
   */
  use(...args: MarkedExtension<ParserOutput, RendererOutput>[]) {
    const extensions: MarkedOptions<ParserOutput, RendererOutput>['extensions'] = this.defaults.extensions || { renderers: {}, childTokens: {} };

    args.forEach((pack) => {
      // copy options to new object
      const opts = { ...pack } as MarkedOptions<ParserOutput, RendererOutput>;

      // set async to true if it was set to true before
      opts.async = this.defaults.async || opts.async || false;

      // ==-- Parse "addon" extensions --== //
      if (pack.extensions) {
        pack.extensions.forEach((ext) => {
          if (!ext.name) {
            throw new Error('extension name required');
          }
          if ('renderer' in ext) { // Renderer extensions
            const prevRenderer = extensions.renderers[ext.name];
            if (prevRenderer) {
              // Replace extension with func to run new extension but fall back if false
              extensions.renderers[ext.name] = function(...args) {
                let ret = ext.renderer.apply(this, args);
                if (ret === false) {
                  ret = prevRenderer.apply(this, args);
                }
                return ret;
              };
            } else {
              extensions.renderers[ext.name] = ext.renderer;
            }
          }
          if ('tokenizer' in ext) { // Tokenizer Extensions
            if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {

View on GitHub (pinned to 9552b6bbca)

Solutions

  1. Add a non-empty name string to every object in the extensions array; the name must match the token type your tokenizer emits and/or your renderer handles.
  2. If you build extensions programmatically, assert each one has a string name before passing the array to use().
  3. Confirm the name is unique among your extensions so a later use() call does not silently chain over it.

Example fix

// before
marked.use({
  extensions: [{
    renderer(token) { return `<x>${token.text}</x>`; }
  }]
});

// after
marked.use({
  extensions: [{
    name: 'x',
    renderer(token) { return `<x>${token.text}</x>`; }
  }]
});
Defensive patterns

Strategy: validation

Validate before calling

function validateExtensions(exts) {
  for (const ext of exts ?? []) {
    if (!ext.name || typeof ext.name !== 'string') {
      throw new TypeError('marked extension missing required "name": ' + JSON.stringify(ext));
    }
  }
}
validateExtensions(myExt.extensions);
marked.use(myExt);

Type guard

function isNamedExtension(ext) {
  return typeof ext?.name === 'string' && ext.name.length > 0;
}

Prevention

When it happens

Trigger: marked.use({ extensions: [{ renderer(token){...} }] }) where the renderer extension has no name; new Marked({ extensions: [{ level:'block', tokenizer(src){...} }] }) where the tokenizer extension has no name; programmatically building the extensions array and pushing an object whose name resolved to undefined; spreading a base extension object but omitting name.

Common situations: Adapting a marked docs example and deleting the name line thinking it was cosmetic; conditionally assembling an extension and forgetting the name branch; migrating from an older marked API where names were optional; refactoring a shared extension constant and removing the name key.

Related errors


AI-assisted analysis of markedjs/marked@9552b6bbca (2026-08-13). Data as JSON: /api/errors/66b270ff40558e9f. Report an issue: GitHub.