{"record":{"id":"1af0b6b2ff07e946","repo":"ruby-concurrency/concurrent-ruby","slug":"executor-not-recognized-by-executor-identifier","errorCode":null,"errorMessage":"executor not recognized by '#{executor_identifier}'","messagePattern":"executor not recognized by '#(.+?)'","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/options.rb","lineNumber":38,"sourceCode":"      if identifier = opts.fetch(:executor, nil)\n        executor(identifier)\n      else\n        nil\n      end\n    end\n\n    def self.executor(executor_identifier)\n      case executor_identifier\n      when :fast\n        Concurrent.global_fast_executor\n      when :io\n        Concurrent.global_io_executor\n      when :immediate\n        Concurrent.global_immediate_executor\n      when Concurrent::ExecutorService\n        executor_identifier\n      else\n        raise ArgumentError, \"executor not recognized by '#{executor_identifier}'\"\n      end\n    end\n  end\nend\n","sourceCodeStart":20,"sourceCodeEnd":43,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/options.rb#L20-L43","documentation":"Concurrent::Options.executor (options.rb:33-41) normalizes the executor: argument accepted by Promises, Agent, Channel and related APIs. It recognizes only the symbols :fast, :io, :immediate, or an object for which executor_identifier.is_a?(Concurrent::ExecutorService) is true; anything else — an unknown symbol, a String, a class/module — raises ArgumentError \"executor not recognized by '...'\".","triggerScenarios":"Concurrent::Promises.future(executor: :quick) { 1 } (unknown symbol); executor: 'io' (String instead of Symbol); executor: 'global_io_executor' or a Symbol loaded from YAML/user input and passed through unvalidated.","commonSituations":"Typos in executor symbols; stringly-typed configuration that is not symbolized or whitelisted; assuming arbitrary executor names are registered globally like Spring bean names.","solutions":["Use one of the three recognized symbols: :fast, :io, or :immediate.","Pass an ExecutorService instance instead: Concurrent.global_io_executor or your own Concurrent::ThreadPoolExecutor.new(...).","Whitelist and symbolize config-sourced executor names before they reach the API."],"exampleFix":"# before\nConcurrent::Promises.future(executor: 'io') { work } # ArgumentError: executor not recognized by 'io'\n\n# after\nConcurrent::Promises.future(executor: :io) { work }\n# or\nConcurrent::Promises.future(executor: Concurrent.global_io_executor) { work }","handlingStrategy":"validation","validationCode":"ALLOWED_EXECUTORS = %i[fast io immediate].freeze\ndef resolve_executor(value)\n  return value if value.is_a?(Concurrent::ExecutorService)\n  return Concurrent::Options.executor(value) if ALLOWED_EXECUTORS.include?(value)\n  raise ArgumentError, \"unknown executor #{value.inspect} (use :fast, :io, :immediate, or an ExecutorService)\"\nend","typeGuard":null,"tryCatchPattern":"begin\n  Concurrent::Promises.future(executor: cfg_executor) { work }\nrescue ArgumentError\n  Concurrent::Promises.future(executor: :io) { work } # safe default\nend","preventionTips":["Whitelist executor names at the config boundary; reject unknown strings early.","Prefer passing ExecutorService instances (e.g. Concurrent.global_io_executor) over symbols from config.","Symbolize stringly-typed executor config before it reaches Promises/Agent."],"tags":["ruby","concurrency","executor","argumenterror","configuration"],"backgroundTag":"invalid-executor-reference","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}