FirefoxOptions should add browser name to the generated capabilities. Otherwise new RemoteWebDriver(url, options.toCapabilities()) sends payload without browserName and grid hub can match it to a node that has no ability to run Firefox.
import static org.openqa.selenium.firefox.FirefoxDriver.BINARY;
import static org.openqa.selenium.firefox.FirefoxDriver.MARIONETTE;
import static org.openqa.selenium.firefox.FirefoxDriver.PROFILE;
+import static org.openqa.selenium.remote.BrowserType.FIREFOX;
import static org.openqa.selenium.remote.CapabilityType.ACCEPT_SSL_CERTS;
+import static org.openqa.selenium.remote.CapabilityType.BROWSER_NAME;
import static org.openqa.selenium.remote.CapabilityType.LOGGING_PREFS;
import static org.openqa.selenium.remote.CapabilityType.PAGE_LOAD_STRATEGY;
import static org.openqa.selenium.remote.CapabilityType.SUPPORTS_WEB_STORAGE;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.firefox.internal.ProfilesIni;
import org.openqa.selenium.logging.LoggingPreferences;
+import org.openqa.selenium.remote.BrowserType;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.io.File;
@@ -478,6 +481,7 @@ private FirefoxProfile extractProfile(Capabilities capabilities) {
public Capabilities toCapabilities() {
HashMap<String, Object> caps = new HashMap<>(desiredCapabilities.asMap());
+ caps.put(BROWSER_NAME, FIREFOX);
if (isLegacy()) {
caps.put(FirefoxDriver.MARIONETTE, false);
