grosser/parallel_tests · error · RuntimeError
Can't pass --failure-exit-code and --highest-exit-status
Error message
Can't pass --failure-exit-code and --highest-exit-status
What it means
Both flags define what exit status parallel_tests itself returns when a child test process fails: --failure-exit-code forces a constant you choose, while --highest-exit-status propagates the largest child exit code. They answer the same question differently, so parse_options! raises when both are present.
Source
Thrown at lib/parallel_tests/cli.rb:384
append_test_options(options, remaining)
options[:group_by] ||= :filesize if options[:only_group]
if options[:group_by] == :found && options[:single_process]
raise "--group-by found and --single-process are not supported"
end
allowed = [:filesize, :runtime, :found]
if !allowed.include?(options[:group_by]) && options[:only_group]
raise "--group-by #{allowed.join(" or ")} is required for --only-group"
end
if options[:specify_groups] && options.keys.intersect?([:single_process, :isolate, :isolate_count])
raise "Can't pass --specify-groups with any of these keys: --single, --isolate, or --isolate-n"
end
if options[:failure_exit_code] && options[:highest_exit_status]
raise "Can't pass --failure-exit-code and --highest-exit-status"
end
options
end
def extract_file_paths(argv)
dash_index = argv.rindex("--")
file_args_at = (dash_index || -1) + 1
[argv[file_args_at..], argv[0...(dash_index || 0)]]
end
def extract_test_options(argv)
dash_index = argv.index("--") || -1
argv[dash_index + 1..]
end
def append_test_options(options, argv)
new_opts = extract_test_options(argv)View on GitHub (pinned to a06047856d)
Solutions
- Pick one strategy: keep --failure-exit-code alone for a fixed CI-recognizable code, or --highest-exit-status alone to propagate child codes
- If the intent was to configure RSpec's own exit code, pass it through to the runner instead: `parallel_test --highest-exit-status -o '--failure-exit-code 42'`
- Prune the duplicated flag from rake tasks / CI env where it crept in
Example fix
# before parallel_test --highest-exit-status --failure-exit-code 42 # after (fixed code) parallel_test --failure-exit-code 42 # after (RSPEC's own flag passed through) parallel_test --highest-exit-status -o '--failure-exit-code 42'
Defensive patterns
Strategy: validation
Validate before calling
opts = ENV.fetch('PARALLEL_TEST_OPTS', '').shellsplit
if opts.include?('--failure-exit-code') && opts.include?('--highest-exit-status')
abort 'parallel_tests: choose either --failure-exit-code or --highest-exit-status, not both'
end Type guard
def exit_status_args_valid?(argv)
!(argv.include?('--failure-exit-code') && argv.include?('--highest-exit-status'))
end Try / catch
begin
ParallelTests::CLI.new.run(args)
rescue RuntimeError => e
abort "#{e.message} -- pass RSpec's own --failure-exit-code after -- or via -o if that was intended"
end Prevention
- Decide the CI exit-status contract once (fixed code vs propagated highest code) and encode it in one place
- Remember RSpec accepts a same-named flag -- pass it through with -o '--failure-exit-code N' instead of at the parallel_tests level
- Lint shared option strings for both flags in CI config review
When it happens
Trigger: `parallel_test --failure-exit-code 42 --highest-exit-status`, or a rake/CI string like PARALLEL_TEST_OPTS="--highest-exit-status --failure-exit-code 1".
Common situations: CI pipelines that already use --highest-exit-status (to distinguish RSpec failure codes from crashes) gain --failure-exit-code when someone copies an RSpec invocation -- RSpec itself accepts a flag of the same name, and passing it after `--` (or via -o as a test option) is legal, which feeds the confusion.
Related errors
- Both options are mutually exclusive: verbose & quiet
- --group-by found and --single-process are not supported
- --group-by #{allowed.join(" or ")} is required for --only-gr
- Can't pass --specify-groups with any of these keys: --single
- Grouping by number of cucumber steps requires the `cuke_mode
AI-assisted analysis of grosser/parallel_tests@a06047856d (2026-08-23).
Data as JSON: /api/errors/ca6d071dc7f952ff.
Report an issue: GitHub.