{"record":{"id":"7bfa874cefa55703","repo":"BetterErrors/better_errors","slug":"expected-editor-to-be-a-valid-editor-key-a-format","errorCode":null,"errorMessage":"Expected editor to be a valid editor key, a format string or a callable.","messagePattern":"Expected editor to be a valid editor key, a format string or a callable\\.","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/better_errors.rb","lineNumber":115,"sourceCode":"  #   a suitable substitute.)\n  #\n  #   @example\n  #     BetterErrors.editor = proc { |file, line|\n  #       \"my-editor://open?url=#{URI.encode_www_form_component file}&line=#{line}\"\n  #     }\n  #\n  #   @param [Proc] proc\n  #\n  def self.editor=(editor)\n    if editor.is_a? Symbol\n      @editor = Editor.editor_from_symbol(editor)\n      raise(ArgumentError, \"Symbol #{editor} is not a symbol in the list of supported errors.\") unless editor\n    elsif editor.is_a? String\n      @editor = Editor.for_formatting_string(editor)\n    elsif editor.respond_to? :call\n      @editor = Editor.for_proc(editor)\n    else\n      raise ArgumentError, \"Expected editor to be a valid editor key, a format string or a callable.\"\n    end\n  end\n\n  # Enables experimental Pry support in the inline REPL\n  #\n  # If you encounter problems while using Pry, *please* file a bug report at\n  # https://github.com/BetterErrors/better_errors/issues\n  def self.use_pry!\n    REPL::PROVIDERS.unshift const: :Pry, impl: \"better_errors/repl/pry\"\n  end\n\n  # Automatically sniffs a default editor preset based on the EDITOR\n  # environment variable.\n  #\n  # @return [Symbol]\n  def self.default_editor\n    Editor.default_editor\n  end","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/BetterErrors/better_errors/blob/fde3b7025db17b5cda13fcf8d08dfb3f76e189f6/lib/better_errors.rb#L97-L133","documentation":"BetterErrors.editor= configures which editor opens when you click a file/line link on the error page, and it only accepts three input shapes: a Symbol naming a supported editor preset (:atom, :emacs, :emacsclient, :idea, :macvim, :mvim, :rubymine, :sublime, :subl, :st, :textmate, :txmt, :tm, :vscode, :code, :vscodium, :codium), a String containing a URL format template with %{file}/%{line} placeholders, or any object responding to #call (a Proc/lambda taking (file, line)). The setter dispatches on those exact types; anything else — nil, a Hash, an Integer, an editor object — falls into the else branch and this ArgumentError is raised at configuration time, before any error page is rendered.","triggerScenarios":"Calling BetterErrors.editor= with a value that is neither Symbol, String, nor #call-responding: e.g. BetterErrors.editor = nil (e.g. ENV[\"EDITOR\"] returned nil and was passed straight through), BetterErrors.editor = 42, BetterErrors.editor = { editor: :vscode } (options Hash instead of the value), or passing a custom editor object that lacks a #call(file, line) method. Typical call sites are an initializer (config/initializers/better_errors.rb), a Gemfile-adjacent setup script, or a test/spec setup block.","commonSituations":"Passing an untrusted env var through without a nil check (EDITOR/BETTER_ERRORS_EDITOR unset in CI); upgrading from an older better_errors version where the accepted shapes differed and a string like \"vscode\" used to be treated as a preset name but is now parsed as a format string; wrapping the editor in a Hash or Struct instead of a lambda when migrating from a string template to a callable; copy-pasting config snippets written for a different library (e.g. pry-byebug style options) into BetterErrors.editor=.","solutions":["Pass one of the supported Symbol presets: BetterErrors.editor = :vscode (or :subl, :atom, :emacs, :idea, :macvim, :rubymine, :textmate, :vscodium).","If you need a custom editor, pass a format String with %{file} and %{line} placeholders: BetterErrors.editor = \"myeditor --goto %{file}:%{line}\".","For dynamic logic, pass a callable: BetterErrors.editor = ->(file, line) { \"myeditor #{file} +#{line}\" } (must respond to #call and take file, line).","If the value comes from ENV, guard it first: BetterErrors.editor = ENV[\"EDITOR\"] || :vscode — a nil env var otherwise hits the else branch and raises.","Check the value's type/respond_to?(:call) before assigning when the config is user-supplied (see validation code below)."],"exampleFix":"# before\nBetterErrors.editor = ENV[\"MY_EDITOR\"]          # nil in CI -> ArgumentError\nBetterErrors.editor = { editor: :vscode }       # Hash -> ArgumentError\n\n# after\nBetterErrors.editor = ENV[\"MY_EDITOR\"] || :vscode\n# or, for a custom command:\nBetterErrors.editor = \"code --goto %{file}:%{line}\"\n# or, for a callable:\nBetterErrors.editor = ->(file, line) { \"code --goto #{file}:#{line}\" }","handlingStrategy":"validation","validationCode":"SUPPORTED_EDITOR_SYMBOLS = [\n  :atom, :emacs, :emacsclient, :idea, :macvim, :mvim, :rubymine,\n  :sublime, :subl, :st, :textmate, :txmt, :tm,\n  :vscode, :code, :vscodium, :codium\n].freeze\n\n# Returns true if the value can be safely assigned to BetterErrors.editor=\ndef valid_better_errors_editor?(value)\n  return true if value.is_a?(String)                       # format string\n  return true if value.respond_to?(:call)                  # proc/lambda\n  value.is_a?(Symbol) && SUPPORTED_EDITOR_SYMBOLS.include?(value)\nend\n\n# Usage in an initializer:\nraw = ENV[\"BETTER_ERRORS_EDITOR_KEY\"]\neditor = raw&.to_sym\nBetterErrors.editor = editor if valid_better_errors_editor?(editor)","typeGuard":"# Ruby has no static types; use a respond_to/is_a? guard before assigning:\ndef set_better_errors_editor(value)\n  unless value.is_a?(Symbol) || value.is_a?(String) || value.respond_to?(:call)\n    raise ArgumentError, \"editor must be a Symbol, format String, or #call-able, got #{value.class}\"\n  end\n  BetterErrors.editor = value\nend","tryCatchPattern":"begin\n  BetterErrors.editor = configured_editor\nrescue ArgumentError => e\n  warn \"better_errors: ignoring invalid editor config (#{e.message}); falling back to default\"\n  BetterErrors.editor = :vscode # safe default preset\nend","preventionTips":["Default env-derived values instead of passing them raw: BetterErrors.editor = ENV[\"EDITOR_SYMBOL\"] || :vscode.","Keep editor config in one initializer/spec helper so a bad value fails once at boot, not scattered across the app.","When migrating configs between better_errors versions, re-check the accepted shapes (Symbol preset, format String, #call-able) — strings like \"vscode\" are format templates, not preset names.","Write a one-line spec asserting your configured editor is assignable (expect { described_class.editor = my_editor }.not_to raise_error) to catch regressions in CI."],"tags":["ruby","better-errors","configuration","argument-error","editor-config"],"backgroundTag":"invalid-argument-type","analyzedSha":"fde3b7025db17b5cda13fcf8d08dfb3f76e189f6","analyzedAt":"2026-08-21T18:46:19.030Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}