BetterErrors/better_errors · error · ArgumentError
Expected editor to be a valid editor key, a format string or
Error message
Expected editor to be a valid editor key, a format string or a callable.
What it means
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.
Source
Thrown at lib/better_errors.rb:115
# a suitable substitute.)
#
# @example
# BetterErrors.editor = proc { |file, line|
# "my-editor://open?url=#{URI.encode_www_form_component file}&line=#{line}"
# }
#
# @param [Proc] proc
#
def self.editor=(editor)
if editor.is_a? Symbol
@editor = Editor.editor_from_symbol(editor)
raise(ArgumentError, "Symbol #{editor} is not a symbol in the list of supported errors.") unless editor
elsif editor.is_a? String
@editor = Editor.for_formatting_string(editor)
elsif editor.respond_to? :call
@editor = Editor.for_proc(editor)
else
raise ArgumentError, "Expected editor to be a valid editor key, a format string or a callable."
end
end
# Enables experimental Pry support in the inline REPL
#
# If you encounter problems while using Pry, *please* file a bug report at
# https://github.com/BetterErrors/better_errors/issues
def self.use_pry!
REPL::PROVIDERS.unshift const: :Pry, impl: "better_errors/repl/pry"
end
# Automatically sniffs a default editor preset based on the EDITOR
# environment variable.
#
# @return [Symbol]
def self.default_editor
Editor.default_editor
endView on GitHub (pinned to fde3b7025d)
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).
Example fix
# before
BetterErrors.editor = ENV["MY_EDITOR"] # nil in CI -> ArgumentError
BetterErrors.editor = { editor: :vscode } # Hash -> ArgumentError
# after
BetterErrors.editor = ENV["MY_EDITOR"] || :vscode
# or, for a custom command:
BetterErrors.editor = "code --goto %{file}:%{line}"
# or, for a callable:
BetterErrors.editor = ->(file, line) { "code --goto #{file}:#{line}" } Defensive patterns
Strategy: validation
Validate before calling
SUPPORTED_EDITOR_SYMBOLS = [ :atom, :emacs, :emacsclient, :idea, :macvim, :mvim, :rubymine, :sublime, :subl, :st, :textmate, :txmt, :tm, :vscode, :code, :vscodium, :codium ].freeze # Returns true if the value can be safely assigned to BetterErrors.editor= def valid_better_errors_editor?(value) return true if value.is_a?(String) # format string return true if value.respond_to?(:call) # proc/lambda value.is_a?(Symbol) && SUPPORTED_EDITOR_SYMBOLS.include?(value) end # Usage in an initializer: raw = ENV["BETTER_ERRORS_EDITOR_KEY"] editor = raw&.to_sym BetterErrors.editor = editor if valid_better_errors_editor?(editor)
Type guard
# Ruby has no static types; use a respond_to/is_a? guard before assigning:
def set_better_errors_editor(value)
unless value.is_a?(Symbol) || value.is_a?(String) || value.respond_to?(:call)
raise ArgumentError, "editor must be a Symbol, format String, or #call-able, got #{value.class}"
end
BetterErrors.editor = value
end Try / catch
begin
BetterErrors.editor = configured_editor
rescue ArgumentError => e
warn "better_errors: ignoring invalid editor config (#{e.message}); falling back to default"
BetterErrors.editor = :vscode # safe default preset
end Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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=.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
AI-assisted analysis of BetterErrors/better_errors@fde3b7025d (2026-08-21).
Data as JSON: /api/errors/7bfa874cefa55703.
Report an issue: GitHub.