{"record":{"id":"97bca949f0739dac","repo":"github/markup","slug":"unknown-commonmarker-option-opt-inspect","errorCode":null,"errorMessage":"unknown commonmarker option: #{opt.inspect}","messagePattern":"unknown commonmarker option: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/github/markup/markdown.rb","lineNumber":50,"sourceCode":"            when :DEFAULT then nil\n            when :SOURCEPOS then render_options[:sourcepos] = true\n            when :HARDBREAKS then render_options[:hardbreaks] = true\n            when :NOBREAKS then render_options[:hardbreaks] = false\n            when :SMART then parse_options[:smart] = true\n            when :GITHUB_PRE_LANG then render_options[:github_pre_lang] = true\n            when :UNSAFE then render_options[:unsafe] = true\n            when :FOOTNOTES then extension_options[:footnotes] = true\n            when :FULL_INFO_STRING then render_options[:full_info_string] = true\n              # The legacy options below existed in cmark-gfm 0.x but have no direct commonmarker\n              # 2.x equivalent. Accept them so existing callers don't break, but they have no effect:\n              #   :VALIDATE_UTF8 / :LIBERAL_HTML_TAG - enforced at the Rust type layer in 2.x.\n              #   :TABLE_PREFER_STYLE_ATTRIBUTES     - no 2.x render knob for inline table styles.\n              #   :STRIKETHROUGH_DOUBLE_TILDE        - 2.x always accepts both single and double tilde.\n            when :VALIDATE_UTF8, :LIBERAL_HTML_TAG,\n                 :TABLE_PREFER_STYLE_ATTRIBUTES, :STRIKETHROUGH_DOUBLE_TILDE\n              nil\n            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","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/github/markup/blob/76e2682193828b98471b3a071edf4db0590ccacb/lib/github/markup/markdown.rb#L32-L68","documentation":"The Markdown implementation backed by commonmarker translates legacy cmark-gfm 0.x option symbols passed via options[:commonmarker_opts] and raises ArgumentError for any symbol outside its whitelist. Accepted: :DEFAULT, :SOURCEPOS, :HARDBREAKS, :NOBREAKS, :SMART, :GITHUB_PRE_LANG, :UNSAFE, :FOOTNOTES, :FULL_INFO_STRING, plus the accepted-but-inert :VALIDATE_UTF8, :LIBERAL_HTML_TAG, :TABLE_PREFER_STYLE_ATTRIBUTES, :STRIKETHROUGH_DOUBLE_TILDE. Anything else - including strings, extension names, or 0.x flags with no 2.x mapping such as :SAFE - raises at render time.","triggerScenarios":"Calling GitHub::Markup.render('f.md', md, options: {commonmarker_opts: [:SAFE]}) or render_s(:markdown, md, options: {commonmarker_opts: ['UNSAFE']}); putting an extension name like :tasklist into commonmarker_opts instead of commonmarker_exts; passing Ruby constants from the old commonmarker 0.x API (Commonmarker::Config::ParseOptions etc.) or misspelled symbols.","commonSituations":"Migrating an app from cmark-gfm/commonmarker 0.x option constants to this wrapper's symbol protocol; copy-pasting option lists from old GitHub::Markup::Markdown::GEM_MAP examples; sending serialized options as JSON so symbols arrive as strings; typos like :SOURCE_POS or :HARDBREAK.","solutions":["Remove or correct the offending symbol: use only the legacy whitelist (:DEFAULT, :SOURCEPOS, :HARDBREAKS, :NOBREAKS, :SMART, :GITHUB_PRE_LANG, :UNSAFE, :FOOTNOTES, :FULL_INFO_STRING, and the inert :VALIDATE_UTF8/:LIBERAL_HTML_TAG/:TABLE_PREFER_STYLE_ATTRIBUTES/:STRIKETHROUGH_DOUBLE_TILDE).","Ensure entries are Symbols, not Strings - 'UNSAFE' raises; :UNSAFE does not.","Move extension names (:table, :autolink, :tasklist, :strikethrough, ...) to options[:commonmarker_exts], which has its own whitelist.","Map removed 0.x flags to their 2.x meaning: raw HTML is controlled by :UNSAFE (there is no :SAFE - omit :UNSAFE instead).","Whitelist-filter user-supplied options before render so bad input cannot raise mid-request."],"exampleFix":"# before\nGitHub::Markup.render_s(:markdown, md, options: {\n  commonmarker_opts: [:SMART, 'UNSAFE', :tasklist]\n})\n# => ArgumentError: unknown commonmarker option: \"UNSAFE\" (and :tasklist is an extension)\n\n# after\nGitHub::Markup.render_s(:markdown, md, options: {\n  commonmarker_opts: [:SMART, :UNSAFE],\n  commonmarker_exts: [:tasklist, :table, :autolink, :strikethrough, :tagfilter]\n})","handlingStrategy":"validation","validationCode":"SUPPORTED_OPTS = %i[DEFAULT SOURCEPOS HARDBREAKS NOBREAKS SMART GITHUB_PRE_LANG\n                    UNSAFE FOOTNOTES FULL_INFO_STRING VALIDATE_UTF8 LIBERAL_HTML_TAG\n                    TABLE_PREFER_STYLE_ATTRIBUTES STRIKETHROUGH_DOUBLE_TILDE].freeze\n\ndef render_markdown(content, opts: [], exts: nil)\n  opts = Array(opts).map(&:to_sym)\n  bad = opts - SUPPORTED_OPTS\n  raise ArgumentError, \"unsupported commonmarker_opts: #{bad.inspect}\" unless bad.empty?\n  options = {commonmarker_opts: opts}\n  options[:commonmarker_exts] = Array(exts).map(&:to_sym) if exts\n  GitHub::Markup.render_s(:markdown, content, options: options)\nend","typeGuard":"# Narrow option input before it reaches the renderer:\ndef valid_commonmarker_opts?(opts)\n  opts = Array(opts)\n  opts.all? { |o| o.is_a?(Symbol) } && (opts - %i[DEFAULT SOURCEPOS HARDBREAKS NOBREAKS SMART\n    GITHUB_PRE_LANG UNSAFE FOOTNOTES FULL_INFO_STRING VALIDATE_UTF8 LIBERAL_HTML_TAG\n    TABLE_PREFER_STYLE_ATTRIBUTES STRIKETHROUGH_DOUBLE_TILDE]).empty?\nend","tryCatchPattern":"begin\n  GitHub::Markup.render_s(:markdown, md, options: {commonmarker_opts: opts})\nrescue ArgumentError => e\n  raise unless e.message.start_with?('unknown commonmarker option:')\n  # strip or report the offending symbol, then retry with sanitized opts\n  cleaned = opts - [e.message[/:(\\S+)/, 1]&.to_sym].compact\n  retry_count += 1\n  retry if (cleaned != opts) && retry_count == 1\n  raise\nend","preventionTips":["Treat the option list as a fixed vocabulary: define one constant in your app and reference only it, never ad-hoc symbols at call sites.","Call .to_sym on anything crossing a serialization boundary (JSON, YAML) before passing it in.","Write a table-driven test that renders with each supported option once; any new symbol then fails in CI, not production.","During the cmark-gfm 0.x to commonmarker 2.x migration, grep for the old option constants and delete ones with no 2.x meaning instead of passing them through."],"tags":["commonmarker","markdown","option-validation","version-migration","ruby"],"backgroundTag":"invalid-option-value","analyzedSha":"76e2682193828b98471b3a071edf4db0590ccacb","analyzedAt":"2026-08-21T19:16:29.859Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}