{"record":{"id":"660c14037d5f5f7a","repo":"markedjs/marked","slug":"extension-level-must-be-block-or-inline","errorCode":null,"errorMessage":"extension level must be 'block' or 'inline'","messagePattern":"extension level must be 'block' or 'inline'","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Instance.ts","lineNumber":131,"sourceCode":"          }\n          if ('renderer' in ext) { // Renderer extensions\n            const prevRenderer = extensions.renderers[ext.name];\n            if (prevRenderer) {\n              // Replace extension with func to run new extension but fall back if false\n              extensions.renderers[ext.name] = function(...args) {\n                let ret = ext.renderer.apply(this, args);\n                if (ret === false) {\n                  ret = prevRenderer.apply(this, args);\n                }\n                return ret;\n              };\n            } else {\n              extensions.renderers[ext.name] = ext.renderer;\n            }\n          }\n          if ('tokenizer' in ext) { // Tokenizer Extensions\n            if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {\n              throw new Error(\"extension level must be 'block' or 'inline'\");\n            }\n            const extLevel = extensions[ext.level];\n            if (extLevel) {\n              extLevel.unshift(ext.tokenizer);\n            } else {\n              extensions[ext.level] = [ext.tokenizer];\n            }\n            if (ext.start) { // Function to check for start of token\n              if (ext.level === 'block') {\n                if (extensions.startBlock) {\n                  extensions.startBlock.push(ext.start);\n                } else {\n                  extensions.startBlock = [ext.start];\n                }\n              } else if (ext.level === 'inline') {\n                if (extensions.startInline) {\n                  extensions.startInline.push(ext.start);\n                } else {","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/markedjs/marked/blob/9552b6bbca7f587f96b7249c5833358a17a18e2b/src/Instance.ts#L113-L149","documentation":"Thrown by Marked.use() when an extension that declares a tokenizer ('tokenizer' in ext is true) has a level that is missing, empty, or not exactly 'block' or 'inline'. The level tells marked where to inject the tokenizer: block tokenizers run in Lexer.blockTokens and inline tokenizers run in Lexer.inlineTokens (Lexer.ts:124-131, 353-360). Without a valid level marked cannot route the tokenizer, so registration is aborted. Renderer-only extensions (no tokenizer) do not need a level and never trigger this.","triggerScenarios":"marked.use({ extensions:[{ name:'x', tokenizer(src){...} }] }) with no level; level:'Block' or 'block-level' (wrong casing/wording, must be lowercase exactly); level:'' or level:undefined; spreading a base extension that had level but overriding it to an invalid value.","commonSituations":"Copying a renderer-extension example and adding a tokenizer without realising level becomes mandatory; assuming the default level is block (there is no default); writing 'Block' for readability; case-sensitivity mistakes.","solutions":["Add level:'block' or level:'inline' (lowercase) to the extension object.","If you only want to change rendering of existing tokens, drop the tokenizer and keep renderer plus name (no level needed).","When building extensions generically, default-fill level from a constant before calling use()."],"exampleFix":"// before\nmarked.use({\n  extensions: [{\n    name: 'mention',\n    tokenizer(src) { const m = /^@(\\w+)/.exec(src); if (!m) return; return { type:'mention', raw:m[0], text:m[1], tokens:[] }; }\n  }]\n});\n\n// after\nmarked.use({\n  extensions: [{\n    name: 'mention',\n    level: 'inline',\n    tokenizer(src) { const m = /^@(\\w+)/.exec(src); if (!m) return; return { type:'mention', raw:m[0], text:m[1], tokens:[] }; }\n  }]\n});","handlingStrategy":"validation","validationCode":"for (const ext of myExt.extensions ?? []) {\n  if ('tokenizer' in ext && ext.level !== 'block' && ext.level !== 'inline') {\n    throw new Error('extension \"' + (ext.name ?? '<unnamed>') + '\" needs level: \\'block\\' | \\'inline\\'');\n  }\n}\nmarked.use(myExt);","typeGuard":"function hasValidLevel(ext) {\n  return !('tokenizer' in ext) || ext.level === 'block' || ext.level === 'inline';\n}","tryCatchPattern":null,"preventionTips":["Treat level as mandatory whenever you write tokenizer: in an extension.","Use the TokenizerExtension type from marked - it marks level as required.","Remember renderer-only extensions are exempt from level."],"tags":["configuration","extensions","tokenizer","validation"],"backgroundTag":null,"analyzedSha":"9552b6bbca7f587f96b7249c5833358a17a18e2b","analyzedAt":"2026-08-13T04:27:55.513Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}