markedjs/marked · error · Error
Token with "${token.type}" type was not found.
Error message
Token with "${token.type}" type was not found. What it means
Thrown in the default branch of the block-token switch in _Parser.parse() when a token's type is not one of the handled block types (space, hr, heading, code, table, blockquote, list, checkbox, html, def, paragraph, text) and is not covered by a registered renderer extension (Parser.ts:50-57, 111-118). With the built-in lexer this is unreachable because it only emits those types. It happens when a custom block-level tokenizer extension produces tokens of a custom type but no matching renderer extension with the same name was registered, or when a caller manually constructs/modifies the token array passed to Parser.parse/marked.parse.
Source
Thrown at src/Parser.ts:117
out += this.renderer.def(token);
break;
}
case 'paragraph': {
out += this.renderer.paragraph(token);
break;
}
case 'text': {
out += this.renderer.text(token);
break;
}
default: {
const errMsg = 'Token with "' + token.type + '" type was not found.';
if (this.options.silent) {
console.error(errMsg);
return '' as ParserOutput;
} else {
throw new Error(errMsg);
}
}
}
}
return out as ParserOutput;
}
/**
* Parse Inline Tokens
*/
parseInline(tokens: Token[], renderer: _Renderer<ParserOutput, RendererOutput> | _TextRenderer<RendererOutput> = this.renderer): ParserOutput {
this.renderer.parser = this;
let out = '';
for (let i = 0; i < tokens.length; i++) {
const anyToken = tokens[i];
View on GitHub (pinned to 9552b6bbca)
Solutions
- Register a renderer extension with name exactly matching the token's type (e.g. extensions:[{ name:'callout', renderer(token){...} }]).
- Verify the casing/whitespace of the type string the tokenizer emits vs the name the renderer uses - they must be byte-identical.
- If hand-building tokens, only use known block token types or also register renderers for custom types.
- Audit any processAllTokens hook to ensure it only injects types that have renderers.
- For debugging, set silent:true to log the unknown type and continue with empty output instead of throwing.
Example fix
// before — tokenizer emits 'callout' but no renderer is registered
marked.use({
extensions: [{
name: 'callout',
level: 'block',
tokenizer(src) { const m = /^:::callout\n([\s\S]*?)\n:::/.exec(src); if (!m) return; return { type:'callout', raw:m[0], text:m[1], tokens:[] }; }
}]
});
// after — add a matching renderer extension
marked.use({
extensions: [
{ name: 'callout', level: 'block', tokenizer(src) { /* ... */ } },
{ name: 'callout', renderer(token) { return `<div class="callout">${this.parser.parse(token.tokens)}</div>`; } }
]
}); Defensive patterns
Strategy: validation
Validate before calling
const knownBlockTypes = new Set(['space','hr','heading','code','table','blockquote','list','checkbox','html','def','paragraph','text']);
const renderedTypes = new Set(Object.keys(markedInstance.defaults.extensions?.renderers ?? {}));
for (const ext of myExtensions) {
if ('tokenizer' in ext && ext.level === 'block' && !knownBlockTypes.has(ext.name) && !renderedTypes.has(ext.name)) {
throw new Error('block extension "' + ext.name + '" has a tokenizer but no renderer');
}
} Type guard
function hasRendererForType(type, markedInstance) {
return ['space','hr','heading','code','table','blockquote','list','checkbox','html','def','paragraph','text'].includes(type)
|| Boolean(markedInstance.defaults.extensions?.renderers?.[type]);
} Try / catch
try {
return marked.parse(md);
} catch (e) {
if (e instanceof Error && /type was not found/.test(e.message)) {
logger.error('Unknown token type encountered; a renderer extension is missing', e.message);
return marked.parse(md, { extensions: null });
}
throw e;
} Prevention
- Always register a renderer extension alongside every custom tokenizer extension, with identical name/type.
- Treat the token type string as the single source of truth that must match the extension name exactly.
- Avoid mutating the token stream in processAllTokens to introduce foreign types.
- Do not feed tokens from other parsers into marked's Parser.parse.
When it happens
Trigger: A block-level tokenizer extension emits { type:'callout', ... } but only the tokenizer was registered (no renderer with name:'callout'), or the renderer was registered under a different name; directly calling marked.Parser.parse(tokens) with a hand-built token array containing an unknown type; a processAllTokens hook injects a token of an unregistered type; name mismatch where the tokenizer emits type:'note' but the renderer extension is name:'Notice'.
Common situations: Building a custom block syntax (admonitions, callouts, diagrams) and forgetting the renderer half; case mismatch between the token type string and the extension name; modifying the token stream in a processAllTokens hook; feeding tokens produced by a different markdown engine into marked's parser.
Related errors
- Infinite loop on byte: ${byte}
- extension name required
- extension level must be 'block' or 'inline'
- renderer '${prop}' does not exist
AI-assisted analysis of markedjs/marked@9552b6bbca (2026-08-13).
Data as JSON: /api/errors/1d14a8fcd2f2773c.
Report an issue: GitHub.