markedjs/marked · error · Error

tokenizer '${prop}' does not exist

Error message

tokenizer '${prop}' does not exist

What it means

Thrown by Marked.use() when the tokenizer object you pass contains a key that is not a method or known property of the _Tokenizer class. Marked iterates the keys with for...in and rejects any prop where !(prop in tokenizer) (Instance.ts:189-191). Allowed keys are the public tokenizer methods (e.g. space, code, fences, heading, hr, blockquote, list, html, def, table, lheading, paragraph, text, escape, tag, link, reflink, emStrong, codespan, br, del, autolink, url, inlineText) plus the ignored options, rules, and lexer. To tokenize NEW syntax use extensions:[{ name, level, tokenizer }] instead of overriding the tokenizer object.

Source

Thrown at src/Instance.ts:191

          const rendererProp = prop as Exclude<keyof _Renderer<ParserOutput, RendererOutput>, 'options' | 'parser'>;
          const rendererFunc = pack.renderer[rendererProp] as GenericRendererFunction;
          const prevRenderer = renderer[rendererProp] as GenericRendererFunction;
          // Replace renderer with func to run extension, but fall back if false
          renderer[rendererProp] = (...args: unknown[]) => {
            let ret = rendererFunc.apply(renderer, args);
            if (ret === false) {
              ret = prevRenderer.apply(renderer, args);
            }
            return (ret || '') as RendererOutput;
          };
        }
        opts.renderer = renderer;
      }
      if (pack.tokenizer) {
        const tokenizer = this.defaults.tokenizer || new _Tokenizer<ParserOutput, RendererOutput>(this.defaults);
        for (const prop in pack.tokenizer) {
          if (!(prop in tokenizer)) {
            throw new Error(`tokenizer '${prop}' does not exist`);
          }
          if (['options', 'rules', 'lexer'].includes(prop)) {
            // ignore options, rules, and lexer properties
            continue;
          }
          const tokenizerProp = prop as Exclude<keyof _Tokenizer<ParserOutput, RendererOutput>, 'options' | 'rules' | 'lexer'>;
          const tokenizerFunc = pack.tokenizer[tokenizerProp] as UnknownFunction;
          const prevTokenizer = tokenizer[tokenizerProp] as UnknownFunction;
          // Replace tokenizer with func to run extension, but fall back if false
          // @ts-expect-error cannot type tokenizer function dynamically
          tokenizer[tokenizerProp] = (...args: unknown[]) => {
            let ret = tokenizerFunc.apply(tokenizer, args);
            if (ret === false) {
              ret = prevTokenizer.apply(tokenizer, args);
            }
            return ret;
          };
        }

View on GitHub (pinned to 9552b6bbca)

Solutions

  1. Rename the key to a real tokenizer method (see allowed list); check exact casing.
  2. For brand-new syntax, move it to extensions:[{ name, level, tokenizer(src){...} }].
  3. Strip helper/utility fields from the tokenizer override object.

Example fix

// before — 'inlineTexts' is not a tokenizer method
marked.use({ tokenizer: { inlineTexts(src) { /* ... */ } } });

// after
marked.use({ tokenizer: { inlineText(src) { /* ... */ } } });
Defensive patterns

Strategy: validation

Validate before calling

import { _Tokenizer } from 'marked';
const ALLOWED = Object.getOwnPropertyNames(_Tokenizer.prototype)
  .filter(k => !['constructor','options','rules','lexer'].includes(k));
for (const prop in myExt.tokenizer ?? {}) {
  if (!ALLOWED.includes(prop)) {
    throw new Error('tokenizer key "' + prop + '" is not a known tokenizer method');
  }
}
marked.use(myExt);

Type guard

function isValidTokenizerKey(prop, tokenizerProto) {
  return prop in tokenizerProto && !['constructor','options','rules','lexer'].includes(prop);
}

Prevention

When it happens

Trigger: marked.use({ tokenizer:{ inlineTexts(src){...} } }) with a typo such as 'inlineTexts' or 'Heading'; overriding a method renamed across marked majors; attaching a helper property to the tokenizer override object; copying a custom-tokenizer snippet intended for extensions into the tokenizer override.

Common situations: Upgrading marked across a major version where tokenizer method names changed; misspelling lowercased concatenated names (inlineText, emStrong); mixing up the two extension mechanisms (override vs addon).

Related errors


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