{"record":{"id":"09455cce9fd8854e","repo":"github/markup","slug":"unknown-commonmarker-extension-ext-inspect","errorCode":null,"errorMessage":"unknown commonmarker extension: #{ext.inspect}","messagePattern":"unknown commonmarker extension: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/github/markup/markdown.rb","lineNumber":67,"sourceCode":"            else\n              raise ArgumentError, \"unknown commonmarker option: #{opt.inspect}\"\n            end\n          end\n\n          legacy_exts.each do |ext|\n            case ext\n            when :strikethrough, :tagfilter, :autolink, :table, :tasklist,\n                 :shortcodes, :footnotes, :multiline_block_quotes,\n                 :math_dollars, :math_code, :wikilinks_title_after_pipe,\n                 :wikilinks_title_before_pipe, :underline, :subscript, :spoiler,\n                 :greentext, :alerts, :description_lists\n              extension_options[ext] = true\n            when :header_ids\n              # header_ids takes a string prefix in 2.x rather than a boolean. The legacy contract\n              # only passed it as a symbol, so use an empty prefix to enable anchor generation.\n              extension_options[:header_ids] = \"\"\n            else\n              raise ArgumentError, \"unknown commonmarker extension: #{ext.inspect}\"\n            end\n          end\n\n          # Several extensions (tagfilter, autolink, table, strikethrough, tasklist, shortcodes)\n          # are enabled by default in commonmarker 2.x but were strictly opt-in in 0.x. Explicitly\n          # disable any extension the caller did not request so behavior matches the legacy contract.\n          [:strikethrough, :tagfilter, :autolink, :table, :tasklist, :shortcodes].each do |ext|\n            extension_options[ext] = false unless extension_options[ext]\n          end\n\n          # header_ids is enabled by default in commonmarker 2.x (it injects anchor tags inside\n          # every heading). The legacy 0.x wrapper never enabled it implicitly, so disable it\n          # unless the caller explicitly requested it.\n          extension_options[:header_ids] = nil unless extension_options.key?(:header_ids)\n\n          Commonmarker.to_html(\n            content,\n            options: {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/github/markup/blob/76e2682193828b98471b3a071edf4db0590ccacb/lib/github/markup/markdown.rb#L49-L85","documentation":"The Markdown implementation raises ArgumentError \"unknown commonmarker extension: #{ext.inspect}\" when options[:commonmarker_exts] contains anything outside the supported extension list: :strikethrough, :tagfilter, :autolink, :table, :tasklist, :shortcodes, :footnotes, :multiline_block_quotes, :math_dollars, :math_code, :wikilinks_title_after_pipe, :wikilinks_title_before_pipe, :underline, :subscript, :spoiler, :greentext, :alerts, :description_lists, and :header_ids (converted to an empty prefix). Unlisted extensions are rejected rather than silently ignored, and note the wrapper explicitly disables defaults (:strikethrough, :tagfilter, :autolink, :table, :tasklist, :shortcodes) unless requested.","triggerScenarios":"Passing options: {commonmarker_exts: [:hardbreaks]} - hardbreaks is a render option, not an extension; passing legacy 0.x option symbols like :STRIKETHROUGH_DOUBLE_TILDE inside commonmarker_exts; sending strings ('table') instead of symbols; inventing extension names like :emoji or :mentions that commonmarker 2.x does not ship.","commonSituations":"Porting extension lists written for cmark-gfm or commonmarker 0.x; storing user rendering preferences as JSON so symbols arrive as strings; assuming a GitHub-flavored feature (e.g. emoji) is a commonmarker extension; typos such as :autolinks or :tasklists.","solutions":["Keep only whitelisted extension symbols in commonmarker_exts (see the case list at markdown.rb:56-65).","Move render/parse knobs to commonmarker_opts (e.g. hardbreaks belongs there as :HARDBREAKS).","Convert strings to symbols before render: exts.map(&:to_sym) - then verify each survives the whitelist.","Whitelist-filter user-provided extension lists so unsupported names are dropped instead of raising mid-request."],"exampleFix":"# before\nGitHub::Markup.render_s(:markdown, md, options: {\n  commonmarker_exts: [:table, 'autolink', :hardbreaks]\n})\n# => ArgumentError: unknown commonmarker extension: \"autolink\" (then :hardbreaks)\n\n# after\nGitHub::Markup.render_s(:markdown, md, options: {\n  commonmarker_opts: [:HARDBREAKS],\n  commonmarker_exts: %i[table autolink tagfilter strikethrough]\n})","handlingStrategy":"validation","validationCode":"SUPPORTED_EXTS = %i[strikethrough tagfilter autolink table tasklist shortcodes footnotes\n                    multiline_block_quotes math_dollars math_code wikilinks_title_after_pipe\n                    wikilinks_title_before_pipe underline subscript spoiler greentext alerts\n                    description_lists header_ids].freeze\n\ndef render_markdown(content, exts: [:table, :autolink, :strikethrough, :tagfilter])\n  exts = Array(exts).map(&:to_sym)\n  bad = exts - SUPPORTED_EXTS\n  raise ArgumentError, \"unsupported commonmarker_exts: #{bad.inspect}\" unless bad.empty?\n  GitHub::Markup.render_s(:markdown, content, options: {commonmarker_exts: exts})\nend","typeGuard":"# Narrow extension input before it reaches the renderer:\ndef valid_commonmarker_exts?(exts)\n  exts = Array(exts)\n  exts.all? { |e| e.is_a?(Symbol) } && (exts - %i[strikethrough tagfilter autolink table\n    tasklist shortcodes footnotes multiline_block_quotes math_dollars math_code\n    wikilinks_title_after_pipe wikilinks_title_before_pipe underline subscript spoiler\n    greentext alerts description_lists header_ids]).empty?\nend","tryCatchPattern":"begin\n  GitHub::Markup.render_s(:markdown, md, options: {commonmarker_exts: exts})\nrescue ArgumentError => e\n  raise unless e.message.start_with?('unknown commonmarker extension:')\n  cleaned = exts.map(&:to_sym) & SUPPORTED_EXTS\n  GitHub::Markup.render_s(:markdown, md, options: {commonmarker_exts: cleaned})\nend","preventionTips":["Keep extensions and options in separate allowlisted constants; never merge user input into either without filtering.","Symbolize (`map(&:to_sym)`) anything that arrived via JSON/YAML before passing it as commonmarker_exts.","Remember the wrapper disables default extensions unless you name them - always pass your full intended ext list explicitly instead of relying on defaults."],"tags":["commonmarker","markdown","extension-validation","version-migration","ruby"],"backgroundTag":"unsupported-extension","analyzedSha":"76e2682193828b98471b3a071edf4db0590ccacb","analyzedAt":"2026-08-21T19:16:29.859Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}