markedjs/marked · error · Error

hook '${prop}' does not exist

Error message

hook '${prop}' does not exist

What it means

Thrown by Marked.use() when the hooks object you pass contains a key that is not a method or known property of the _Hooks class. Marked iterates the keys and rejects any prop with !(prop in hooks) (Instance.ts:216-218). Allowed hook methods are preprocess, postprocess, processAllTokens, emStrongMask, provideLexer, provideParser, plus the ignored options and block. The first four are pass-through hooks that chain return values; provideLexer/provideParser let you swap the lexer/parser functions. There is no generic lifecycle hook API beyond these six.

Source

Thrown at src/Instance.ts:218

          // 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;
          };
        }
        opts.tokenizer = tokenizer;
      }

      // ==-- Parse Hooks extensions --== //
      if (pack.hooks) {
        const hooks = this.defaults.hooks || new _Hooks<ParserOutput, RendererOutput>();
        for (const prop in pack.hooks) {
          if (!(prop in hooks)) {
            throw new Error(`hook '${prop}' does not exist`);
          }
          if (['options', 'block'].includes(prop)) {
            // ignore options and block properties
            continue;
          }
          const hooksProp = prop as Exclude<keyof _Hooks<ParserOutput, RendererOutput>, 'options' | 'block'>;
          const hooksFunc = pack.hooks[hooksProp] as UnknownFunction;
          const prevHook = hooks[hooksProp] as UnknownFunction;
          if (_Hooks.passThroughHooks.has(prop)) {
            // @ts-expect-error cannot type hook function dynamically
            hooks[hooksProp] = (arg: unknown) => {
              if (this.defaults.async && _Hooks.passThroughHooksRespectAsync.has(prop)) {
                return (async() => {
                  const ret = await hooksFunc.call(hooks, arg);
                  return prevHook.call(hooks, ret);
                })();
              }

View on GitHub (pinned to 9552b6bbca)

Solutions

  1. Rename the key to a supported hook: preprocess, postprocess, processAllTokens, emStrongMask, provideLexer, or provideParser.
  2. If you need custom logic at an unsupported point, use walkTokens or a renderer/tokenizer extension instead.
  3. Remove non-hook helper fields from the hooks object.

Example fix

// before — 'beforeRender' is not a real hook
marked.use({ hooks: { beforeRender(md) { return md.trim(); } } });

// after — 'preprocess' is the supported pass-through hook
marked.use({ hooks: { preprocess(md) { return md.trim(); } } });
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = ['preprocess','postprocess','processAllTokens','emStrongMask','provideLexer','provideParser'];
for (const prop in myExt.hooks ?? {}) {
  if (!ALLOWED.includes(prop)) {
    throw new Error('hook "' + prop + '" is not supported; use one of: ' + ALLOWED.join(', '));
  }
}
marked.use(myExt);

Type guard

function isValidHookKey(prop) {
  return ['preprocess','postprocess','processAllTokens','emStrongMask','provideLexer','provideParser'].includes(prop);
}

Prevention

When it happens

Trigger: marked.use({ hooks:{ prepocess(md){...} } }) with a typo (prepocess vs preprocess); inventing a hook name like beforeParse or onToken that does not exist; copying a hook name from another markdown library's API.

Common situations: Assuming marked supports lifecycle hooks it does not have; misspelling processAllTokens (camelCase) or emStrongMask; version drift from a plugin example written for a different marked version.

Related errors


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