{"record":{"id":"1c45dd9ab77b88fe","repo":"markedjs/marked","slug":"hook-prop-does-not-exist","errorCode":null,"errorMessage":"hook '${prop}' does not exist","messagePattern":"hook '(.+?)' does not exist","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Instance.ts","lineNumber":218,"sourceCode":"          // Replace tokenizer with func to run extension, but fall back if false\n          // @ts-expect-error cannot type tokenizer function dynamically\n          tokenizer[tokenizerProp] = (...args: unknown[]) => {\n            let ret = tokenizerFunc.apply(tokenizer, args);\n            if (ret === false) {\n              ret = prevTokenizer.apply(tokenizer, args);\n            }\n            return ret;\n          };\n        }\n        opts.tokenizer = tokenizer;\n      }\n\n      // ==-- Parse Hooks extensions --== //\n      if (pack.hooks) {\n        const hooks = this.defaults.hooks || new _Hooks<ParserOutput, RendererOutput>();\n        for (const prop in pack.hooks) {\n          if (!(prop in hooks)) {\n            throw new Error(`hook '${prop}' does not exist`);\n          }\n          if (['options', 'block'].includes(prop)) {\n            // ignore options and block properties\n            continue;\n          }\n          const hooksProp = prop as Exclude<keyof _Hooks<ParserOutput, RendererOutput>, 'options' | 'block'>;\n          const hooksFunc = pack.hooks[hooksProp] as UnknownFunction;\n          const prevHook = hooks[hooksProp] as UnknownFunction;\n          if (_Hooks.passThroughHooks.has(prop)) {\n            // @ts-expect-error cannot type hook function dynamically\n            hooks[hooksProp] = (arg: unknown) => {\n              if (this.defaults.async && _Hooks.passThroughHooksRespectAsync.has(prop)) {\n                return (async() => {\n                  const ret = await hooksFunc.call(hooks, arg);\n                  return prevHook.call(hooks, ret);\n                })();\n              }\n","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/markedjs/marked/blob/9552b6bbca7f587f96b7249c5833358a17a18e2b/src/Instance.ts#L200-L236","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rename the key to a supported hook: preprocess, postprocess, processAllTokens, emStrongMask, provideLexer, or provideParser.","If you need custom logic at an unsupported point, use walkTokens or a renderer/tokenizer extension instead.","Remove non-hook helper fields from the hooks object."],"exampleFix":"// before — 'beforeRender' is not a real hook\nmarked.use({ hooks: { beforeRender(md) { return md.trim(); } } });\n\n// after — 'preprocess' is the supported pass-through hook\nmarked.use({ hooks: { preprocess(md) { return md.trim(); } } });","handlingStrategy":"validation","validationCode":"const ALLOWED = ['preprocess','postprocess','processAllTokens','emStrongMask','provideLexer','provideParser'];\nfor (const prop in myExt.hooks ?? {}) {\n  if (!ALLOWED.includes(prop)) {\n    throw new Error('hook \"' + prop + '\" is not supported; use one of: ' + ALLOWED.join(', '));\n  }\n}\nmarked.use(myExt);","typeGuard":"function isValidHookKey(prop) {\n  return ['preprocess','postprocess','processAllTokens','emStrongMask','provideLexer','provideParser'].includes(prop);\n}","tryCatchPattern":null,"preventionTips":["Use the HooksObject type - its keys are constrained to the real hook API.","Remember the supported hooks are fixed to the six listed; there is no generic lifecycle.","preprocess/postprocess/processAllTokens/emStrongMask are pass-through (return value chains); provideLexer/provideParser swap implementations."],"tags":["configuration","hooks","typo","validation","marked-use"],"backgroundTag":null,"analyzedSha":"9552b6bbca7f587f96b7249c5833358a17a18e2b","analyzedAt":"2026-08-13T04:27:55.513Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}