{"record":{"id":"1d14a8fcd2f2773c","repo":"markedjs/marked","slug":"token-with-token-type-type-was-not-found","errorCode":null,"errorMessage":"Token with \"${token.type}\" type was not found.","messagePattern":"Token with \"(.+?)\" type was not found\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Parser.ts","lineNumber":117,"sourceCode":"          out += this.renderer.def(token);\n          break;\n        }\n        case 'paragraph': {\n          out += this.renderer.paragraph(token);\n          break;\n        }\n        case 'text': {\n          out += this.renderer.text(token);\n          break;\n        }\n\n        default: {\n          const errMsg = 'Token with \"' + token.type + '\" type was not found.';\n          if (this.options.silent) {\n            console.error(errMsg);\n            return '' as ParserOutput;\n          } else {\n            throw new Error(errMsg);\n          }\n        }\n      }\n    }\n\n    return out as ParserOutput;\n  }\n\n  /**\n   * Parse Inline Tokens\n   */\n  parseInline(tokens: Token[], renderer: _Renderer<ParserOutput, RendererOutput> | _TextRenderer<RendererOutput> = this.renderer): ParserOutput {\n    this.renderer.parser = this;\n    let out = '';\n\n    for (let i = 0; i < tokens.length; i++) {\n      const anyToken = tokens[i];\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/markedjs/marked/blob/9552b6bbca7f587f96b7249c5833358a17a18e2b/src/Parser.ts#L99-L135","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","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."],"exampleFix":"// before — tokenizer emits 'callout' but no renderer is registered\nmarked.use({\n  extensions: [{\n    name: 'callout',\n    level: 'block',\n    tokenizer(src) { const m = /^:::callout\\n([\\s\\S]*?)\\n:::/.exec(src); if (!m) return; return { type:'callout', raw:m[0], text:m[1], tokens:[] }; }\n  }]\n});\n\n// after — add a matching renderer extension\nmarked.use({\n  extensions: [\n    { name: 'callout', level: 'block', tokenizer(src) { /* ... */ } },\n    { name: 'callout', renderer(token) { return `<div class=\"callout\">${this.parser.parse(token.tokens)}</div>`; } }\n  ]\n});","handlingStrategy":"validation","validationCode":"const knownBlockTypes = new Set(['space','hr','heading','code','table','blockquote','list','checkbox','html','def','paragraph','text']);\nconst renderedTypes = new Set(Object.keys(markedInstance.defaults.extensions?.renderers ?? {}));\nfor (const ext of myExtensions) {\n  if ('tokenizer' in ext && ext.level === 'block' && !knownBlockTypes.has(ext.name) && !renderedTypes.has(ext.name)) {\n    throw new Error('block extension \"' + ext.name + '\" has a tokenizer but no renderer');\n  }\n}","typeGuard":"function hasRendererForType(type, markedInstance) {\n  return ['space','hr','heading','code','table','blockquote','list','checkbox','html','def','paragraph','text'].includes(type)\n    || Boolean(markedInstance.defaults.extensions?.renderers?.[type]);\n}","tryCatchPattern":"try {\n  return marked.parse(md);\n} catch (e) {\n  if (e instanceof Error && /type was not found/.test(e.message)) {\n    logger.error('Unknown token type encountered; a renderer extension is missing', e.message);\n    return marked.parse(md, { extensions: null });\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["parser","runtime","extensions","renderer","token-type"],"backgroundTag":null,"analyzedSha":"9552b6bbca7f587f96b7249c5833358a17a18e2b","analyzedAt":"2026-08-13T04:27:55.513Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}