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
- Rename the key to a real tokenizer method (see allowed list); check exact casing.
- For brand-new syntax, move it to extensions:[{ name, level, tokenizer(src){...} }].
- 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
- Use the TokenizerObject type so TS constrains the keys.
- Confirm method names against the Tokenizer API docs for your marked version.
- Prefer extensions: for new syntax; reserve tokenizer: overrides for changing built-in behaviour.
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
- renderer '${prop}' does not exist
- hook '${prop}' does not exist
- extension name required
- extension level must be 'block' or 'inline'
- Infinite loop on byte: ${byte}
AI-assisted analysis of markedjs/marked@9552b6bbca (2026-08-13).
Data as JSON: /api/errors/fbfd2de826895013.
Report an issue: GitHub.