github/markup · error · ArgumentError
unknown commonmarker option: #{opt.inspect}
Error message
unknown commonmarker option: #{opt.inspect} What it means
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.
Source
Thrown at lib/github/markup/markdown.rb:50
when :DEFAULT then nil
when :SOURCEPOS then render_options[:sourcepos] = true
when :HARDBREAKS then render_options[:hardbreaks] = true
when :NOBREAKS then render_options[:hardbreaks] = false
when :SMART then parse_options[:smart] = true
when :GITHUB_PRE_LANG then render_options[:github_pre_lang] = true
when :UNSAFE then render_options[:unsafe] = true
when :FOOTNOTES then extension_options[:footnotes] = true
when :FULL_INFO_STRING then render_options[:full_info_string] = true
# The legacy options below existed in cmark-gfm 0.x but have no direct commonmarker
# 2.x equivalent. Accept them so existing callers don't break, but they have no effect:
# :VALIDATE_UTF8 / :LIBERAL_HTML_TAG - enforced at the Rust type layer in 2.x.
# :TABLE_PREFER_STYLE_ATTRIBUTES - no 2.x render knob for inline table styles.
# :STRIKETHROUGH_DOUBLE_TILDE - 2.x always accepts both single and double tilde.
when :VALIDATE_UTF8, :LIBERAL_HTML_TAG,
:TABLE_PREFER_STYLE_ATTRIBUTES, :STRIKETHROUGH_DOUBLE_TILDE
nil
else
raise ArgumentError, "unknown commonmarker option: #{opt.inspect}"
end
end
legacy_exts.each do |ext|
case ext
when :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
extension_options[ext] = true
when :header_ids
# header_ids takes a string prefix in 2.x rather than a boolean. The legacy contract
# only passed it as a symbol, so use an empty prefix to enable anchor generation.
extension_options[:header_ids] = ""
else
raise ArgumentError, "unknown commonmarker extension: #{ext.inspect}"
endView on GitHub (pinned to 76e2682193)
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.
Example fix
# before
GitHub::Markup.render_s(:markdown, md, options: {
commonmarker_opts: [:SMART, 'UNSAFE', :tasklist]
})
# => ArgumentError: unknown commonmarker option: "UNSAFE" (and :tasklist is an extension)
# after
GitHub::Markup.render_s(:markdown, md, options: {
commonmarker_opts: [:SMART, :UNSAFE],
commonmarker_exts: [:tasklist, :table, :autolink, :strikethrough, :tagfilter]
}) Defensive patterns
Strategy: validation
Validate before calling
SUPPORTED_OPTS = %i[DEFAULT SOURCEPOS HARDBREAKS NOBREAKS SMART GITHUB_PRE_LANG
UNSAFE FOOTNOTES FULL_INFO_STRING VALIDATE_UTF8 LIBERAL_HTML_TAG
TABLE_PREFER_STYLE_ATTRIBUTES STRIKETHROUGH_DOUBLE_TILDE].freeze
def render_markdown(content, opts: [], exts: nil)
opts = Array(opts).map(&:to_sym)
bad = opts - SUPPORTED_OPTS
raise ArgumentError, "unsupported commonmarker_opts: #{bad.inspect}" unless bad.empty?
options = {commonmarker_opts: opts}
options[:commonmarker_exts] = Array(exts).map(&:to_sym) if exts
GitHub::Markup.render_s(:markdown, content, options: options)
end Type guard
# Narrow option input before it reaches the renderer:
def valid_commonmarker_opts?(opts)
opts = Array(opts)
opts.all? { |o| o.is_a?(Symbol) } && (opts - %i[DEFAULT SOURCEPOS HARDBREAKS NOBREAKS SMART
GITHUB_PRE_LANG UNSAFE FOOTNOTES FULL_INFO_STRING VALIDATE_UTF8 LIBERAL_HTML_TAG
TABLE_PREFER_STYLE_ATTRIBUTES STRIKETHROUGH_DOUBLE_TILDE]).empty?
end Try / catch
begin
GitHub::Markup.render_s(:markdown, md, options: {commonmarker_opts: opts})
rescue ArgumentError => e
raise unless e.message.start_with?('unknown commonmarker option:')
# strip or report the offending symbol, then retry with sanitized opts
cleaned = opts - [e.message[/:(\S+)/, 1]&.to_sym].compact
retry_count += 1
retry if (cleaned != opts) && retry_count == 1
raise
end Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- unknown commonmarker extension: #{ext.inspect}
- no suitable markdown gem found
- stderr
- Can not render a nil.
- The '#{symbol}' symbol is already defined.
AI-assisted analysis of github/markup@76e2682193 (2026-08-21).
Data as JSON: /api/errors/97bca949f0739dac.
Report an issue: GitHub.