PRACTICAL GUIDE / Selenium DevTools version warning fix

Fix the Selenium CDP warning without guessing at versions

Find whether a Selenium CDP warning is harmless or breaking, align Java dependencies with Chrome, test the exact feature, and stop CI drift.

By The Testing AcademyUpdated August 4, 202618 min read
All field guides
In this guide7 sections
  1. Read the warning as a classpath diagnosis
  2. Record the versions that actually met in CI
  3. Align the release before adding a protocol artifact
  4. Make the compatibility test fail for a real mismatch
  5. Move supported use cases toward WebDriver BiDi
  6. Work through the failures an upgrade can expose
  7. Keep browser drift visible in CI

What you will learn

  • Read the warning as a classpath diagnosis
  • Record the versions that actually met in CI
  • Align the release before adding a protocol artifact
  • Make the compatibility test fail for a real mismatch

Chrome updated overnight, and the Java suite now prints a CDP mismatch warning before the first test. Ordinary navigation still works, but the test that listens for network traffic no longer receives an event. Updating ChromeDriver alone may not change either result because the driver handshake and Selenium’s CDP model are separate compatibility boundaries.

Read the warning as a classpath diagnosis

Selenium Java controls Chromium through more than one protocol. Normal WebDriver commands create a session, navigate, find elements, click, type, and manage windows through the WebDriver protocol. DevTools features use the Chrome DevTools Protocol, usually called CDP. A browser and driver can agree well enough to create a WebDriver session while the Java client lacks an exact generated model for that browser’s CDP version.

The distinction changes the first response. A session-creation error that names the browser and driver versions is a browser-driver problem. A warning from org.openqa.selenium.devtools.CdpVersionFinder is about Selenium’s available CDP implementations. A missing event after a successful session may be a CDP or BiDi feature problem. An element timeout on an unrelated page is not connected merely because the warning appears earlier in the console.

Current Selenium Java discovers CDP implementations on the runtime classpath and compares their major versions with the Chromium major version. An exact match is preferred. When no exact implementation is available, the warning tells you whether Selenium selected a lower nearby implementation or could not find a matching implementation at all. Those two messages carry different risk.

A closest-version warning means Selenium found a generated model it considers near enough to return. It does not guarantee that every command, parameter, event, and response used by your suite is compatible. A no-match warning means CDP domain access can fall back to a no-operation implementation, so code that needs typed domains should be treated as unsupported until proved otherwise. Do not turn either statement into a claim that the entire Selenium session is broken.

The warning is emitted when Selenium needs to resolve a DevTools implementation. That may happen during creation or first use depending on the driver path and feature. Keep the complete log around the first DevTools call. If a later exception names NoOpDomains, DevToolsException, a missing generated class, or an unrecognized protocol field, preserve that stack trace. The warning alone has less diagnostic value than the warning plus the feature call that followed it.

Three examples show why classification matters. A login test that only uses get, findElement, and click may pass despite the warning. Its product assertions remain meaningful. A performance test that imports a versioned org.openqa.selenium.devtools.vNN package has a direct dependency on that generated model, so a browser update can break compilation or runtime behavior. A Grid test that fails before receiving a session ID has not reached CDP model selection at all and needs a session-creation investigation.

Do not copy a dependency line from an old forum answer. CDP artifact names include a browser protocol major, while the artifact version belongs to a Selenium release. The requested browser major may not be published by the Selenium release currently in your project. Combining an arbitrary selenium-devtools-vNN artifact with a different selenium-java version can create binary incompatibility instead of fixing it.

Record the versions that actually met in CI

Collect four facts from the failing process, not from a developer’s browser settings page. Record the Selenium release loaded at runtime, the browser version returned in session capabilities, the driver version where available, and the CDP version capability where Grid or the driver reports one. Also record the Java dependency tree. A parent POM, framework starter, or transitive dependency can override the version you believe you declared.

The following class prints bounded compatibility evidence. It does not open a DevTools session, and it does not claim that an exact model exists. The output is safe for ordinary CI logs because it contains versions and session capability values, not page content or tokens.

Java
package example.devtools;

import java.util.Map;
import org.openqa.selenium.BuildInfo;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.chrome.ChromeDriver;

public final class SeleniumRuntimeReport {
  public static void main(String[] args) {
    ChromeDriver driver = new ChromeDriver();
    try {
      Capabilities caps = driver.getCapabilities();
      System.out.printf("selenium=%s%n", new BuildInfo().getReleaseLabel());
      System.out.printf("browser=%s %s%n", caps.getBrowserName(), caps.getBrowserVersion());
      System.out.printf("cdpVersion=%s%n", caps.getCapability("se:cdpVersion"));
      Object chromeDetails = caps.getCapability("chrome");
      Object driverVersion =
          chromeDetails instanceof Map<?, ?> details
              ? details.get("chromedriverVersion")
              : null;
      System.out.printf("chromedriver=%s%n", driverVersion);
    } finally {
      driver.quit();
    }
  }
}

For local Chrome, the chrome capability commonly contains driver details, but treat that map as diagnostic data rather than a cross-browser contract. On Grid, returned capabilities can also include Selenium extension keys. Keep the raw capability map in a restricted artifact if you need it, because vendor extensions and paths may disclose internal hosts or profile locations.

Pair runtime facts with build facts. Maven’s dependency tree reveals mixed Selenium modules and exclusions. The packaged JAR inspection catches a different failure: dependencies work in the IDE, then disappear or lose service-provider metadata during shading.

Shell
#!/usr/bin/env bash
set -euo pipefail

mkdir -p target

./mvnw -B dependency:tree \
  -Dincludes=org.seleniumhq.selenium \
  -Dverbose \
  | tee target/selenium-dependency-tree.txt

if command -v google-chrome >/dev/null 2>&1; then
  google-chrome --version
elif command -v chromium >/dev/null 2>&1; then
  chromium --version
else
  echo "No local Chromium executable found; use returned Grid capabilities" >&2
fi

jar_file="${1:-}"
if [[ -n "$jar_file" ]]; then
  test -f "$jar_file"
  jar tf "$jar_file" \
    | grep -E 'META-INF/services/org\.openqa\.selenium\.devtools\.CdpInfo|selenium-devtools' \
    || {
      echo "Packaged JAR contains no visible CDP provider metadata" >&2
      exit 1
    }
fi

Do not compare only Chrome and ChromeDriver. Selenium Manager can resolve a compatible driver while the Java binding remains too old for the browser’s CDP model. Conversely, a correct Selenium CDP binding cannot rescue a driver that cannot create a session with the installed browser. Keep both checks in the incident record.

Watch for split versions. selenium-api, selenium-remote-driver, selenium-chrome-driver, selenium-support, and DevTools artifacts should come from a coherent Selenium release. A dependency tree with several Selenium release numbers deserves correction even if the current test happens to pass. Java linkage errors often appear only when a less common code path calls a method that changed between those releases.

A fat JAR adds another boundary. Selenium uses Java service-provider metadata to discover CDP implementations. Some shading configurations keep only one file when several dependencies contribute the same META-INF/services path. The IDE classpath has every original JAR, so discovery works there; the packaged artifact has an incomplete merged file, so it warns. Configure the packaging tool to merge service descriptors, then run the packaged artifact in CI. Merely adding another dependency will not repair destructive packaging.

Align the release before adding a protocol artifact

For a normal Maven project that depends on selenium-java, the first fix is to move the whole Selenium dependency set to a release that supports the browser major in your environment. Use one version property, refresh the resolved dependencies, and confirm the tree. The official Selenium installation page shows the supported selenium-java dependency form and current release.

Do the upgrade on a branch with the browser matrix visible. Selenium releases can change more than generated CDP models. A rushed production suite upgrade may expose Java baseline changes, deprecations, Grid compatibility changes, or different browser-management behavior. Run ordinary WebDriver tests and the exact DevTools feature smoke together.

If your organization cannot upgrade Selenium immediately, pin or hold the browser image at a supported major for the affected job. That exchanges security and maintenance flexibility for short-term stability, so it needs an owner and expiry date. Do not hold employee browsers or internet-facing production systems back merely to protect a test. A controlled CI container or Grid node image is the appropriate scope.

A direct selenium-devtools-vNN dependency is a specialist fix. It makes sense when the project intentionally uses smaller Selenium modules, when a versioned package is imported directly, or when packaging excluded a binding that exists for the same Selenium release. Before adding it, verify that the artifact exists, that NN matches the required browser protocol major, and that its artifact version is exactly aligned with the rest of Selenium.

Never change only the NN portion while leaving an unrelated artifact version copied from an example. Generated domain classes call shared Selenium code. Mixing releases can compile in one module and fail at runtime in another. The dependency tree, not the POM snippet, is the final record of what Maven selected.

The cleanest fix may be removing the CDP dependency. Teams often use DevTools to read information already visible through stable WebDriver behavior or an application test API. If a test only needs to know that an error banner rendered, assert the banner. If it only needs an HTTP outcome owned by your backend, test that API directly. Avoid a browser protocol subscription whose event is not part of the requirement.

Take special care with versioned imports. A source file containing org.openqa.selenium.devtools.vNN.network.Network declares that browser protocol model in code. Updating the browser may require changing imports, method parameters, and model types. Selenium’s idealized or higher-level APIs can reduce that coupling for supported use cases, while WebDriver BiDi is the standards-track direction documented by Selenium. Migration still requires a feature-by-feature check.

The upgrade cost is real. A current Selenium release may force framework changes, while a pinned browser increases image maintenance and delays browser coverage. A manual DevTools module gives short-term control but keeps the suite tied to Chromium majors. Record which cost the team accepted and when it will reconsider the choice.

Make the compatibility test fail for a real mismatch

Do not gate CI by searching for the word WARNING alone. Libraries, drivers, and the JDK emit warnings for unrelated reasons, and log wording can change. Build a small test that asks the same version finder Selenium uses which CDP model it selected, then requires an exact major only for jobs that depend on typed CDP features.

This JUnit test starts Chrome, obtains the browser version from capabilities, asks CdpVersionFinder for the selected implementation, and compares majors. A browser update or missing provider can make it fail. It is intentionally stricter than Selenium’s nearest-match behavior because the example suite has chosen exact CDP support as a release requirement.

Java
package example.devtools;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.CdpInfo;
import org.openqa.selenium.devtools.CdpVersionFinder;

final class ExactCdpBindingTest {
  @Test
  void runtime_classpath_contains_an_exact_binding_for_chrome() {
    ChromeDriver driver = new ChromeDriver();
    try {
      Capabilities caps = driver.getCapabilities();
      int browserMajor = Integer.parseInt(caps.getBrowserVersion().split("\\.")[0]);
      Optional<CdpInfo> selected = new CdpVersionFinder().match(caps.getBrowserVersion());

      assertTrue(
          selected.isPresent(),
          () -> "No CDP implementation found for Chrome " + caps.getBrowserVersion()
      );
      assertEquals(
          browserMajor,
          selected.orElseThrow().getMajorVersion(),
          "Selenium selected a non-exact CDP implementation"
      );
    } finally {
      driver.quit();
    }
  }
}

That test is not enough on its own. An exact generated model can still encounter a browser regression, an unsupported endpoint, a Grid WebSocket problem, or a packaging defect elsewhere. Add one functional probe for the capability your suite really uses. A network suite should observe a request from an organization-owned page. A console suite should receive a known log entry. An emulation suite should assert the page-visible effect of its command.

Use a test page you control. Public demo pages can change and turn a compatibility gate into an internet availability monitor. The functional probe should produce one known event, wait with a bounded timeout, and assert an identifying field. It should not pass merely because no exception was thrown.

There is also a useful negative case. Run one ordinary WebDriver smoke test without touching DevTools. If exact-CDP compatibility fails while the WebDriver smoke passes, the report tells maintainers which part of the suite is blocked. If both fail before session creation, stop investigating CdpVersionFinder and repair the browser-driver or Grid boundary.

Avoid calling getDevTools() as the entire oracle. Obtaining an object does not prove that the requested domain command or event works. Likewise, creating a CDP session proves a connection, not semantic compatibility for every domain. Exercise the one command and response shape that matters to your tests.

Move supported use cases toward WebDriver BiDi

Selenium documents CDP support as temporary while WebDriver BiDi grows. BiDi is a standards-track bidirectional protocol designed for commands and events across browsers. Migration reduces direct dependence on Chromium’s numbered protocol models, but it does not mean every CDP use case already has an equivalent.

Inventory each CDP feature by purpose. “Network domain” is too broad. Recording request method and URL, intercepting before a request, setting authentication, and reading response bodies have different support and behavior. Match the exact operation against Selenium’s current high-level BiDi documentation. Do not replace a working CDP call with a similarly named BiDi call and assume identical timing or coverage.

The next example uses Selenium’s documented high-level BiDi network module to prove that an owned navigation emits a request event. The webSocketUrl capability requests BiDi for the session. The listener accepts only the configured target URL, then the assertions check its browsing context, URL, and method. An unrelated request from the same tab cannot satisfy the oracle.

Java
package example.devtools;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.BeforeRequestSent;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

final class BidiNetworkSmokeTest {
  @Test
  void navigation_emits_a_before_request_event() throws Exception {
    ChromeOptions options = new ChromeOptions();
    options.setCapability("webSocketUrl", true);
    ChromeDriver driver = new ChromeDriver(options);

    try (Network network = new Network(driver)) {
      String target = System.getenv("BIDI_SMOKE_URL");
      if (target == null || target.isBlank()) {
        throw new IllegalStateException("BIDI_SMOKE_URL must be set");
      }
      CompletableFuture<BeforeRequestSent> event = new CompletableFuture<>();
      network.onBeforeRequestSent(
          observed -> {
            if (target.equals(observed.getRequest().getUrl())) {
              event.complete(observed);
            }
          }
      );

      driver.get(target);
      BeforeRequestSent observed = event.get(10, TimeUnit.SECONDS);

      assertEquals(driver.getWindowHandle(), observed.getBrowsingContextId());
      assertEquals(target, observed.getRequest().getUrl());
      assertEquals("get", observed.getRequest().getMethod().toLowerCase());
    } finally {
      driver.quit();
    }
  }
}

Use the high-level modules Selenium recommends. Low-level classes that map directly to wire protocol structures may be public for implementation reasons while still being marked internal. An IDE deprecation or internal-API warning is not cosmetic. It means the code accepts a higher migration burden.

BiDi has trade-offs. Browser implementations can mature at different rates. A Grid needs to carry the WebSocket connection correctly. Event ordering or available fields may differ from CDP. A migration can expand cross-browser coverage while losing a Chromium-specific field the test used. Run old and new probes side by side for a short period and compare assertions, not event counts.

Keep CDP where no supported BiDi or WebDriver alternative exists and the business value justifies the coupling. Wrap it behind a small adapter, centralize versioned imports, and give that adapter its own compatibility test. Scattering vNN imports across page objects turns every browser update into a repository-wide edit.

Work through the failures an upgrade can expose

The easiest case is a browser channel moving ahead of the bindings on an otherwise coherent classpath. The dependency tree shows one Selenium release, the packaged and IDE runs behave the same, classic WebDriver passes, and the exact-binding test reports a lower selected CDP major or no model. Check the supported models in a newer Selenium release. If support exists, upgrade the unified dependency property and run the feature probe. If it does not exist yet, keep that browser in a canary or temporarily hold the controlled test image. Inventing an artifact name cannot publish code that the Selenium release does not contain.

A packaged-only failure has a different fingerprint. The IDE reports an exact binding and the feature works. The executable JAR uses the same browser but reports no implementation. dependency:tree looks correct because Maven resolved the dependencies before packaging. Inspect the final archive and its service descriptors. If the shade or assembly step discarded providers with duplicate paths, configure that tool's documented service-resource merge and rebuild. Run the final JAR, not a test class on Maven's original classpath, as the proof. This failure can survive every ordinary unit test because those tests never load the packaged layout.

Mixed releases often start with a framework dependency. The project declares a current selenium-java, while an older reporting or Grid helper constrains selenium-remote-driver or excludes the DevTools modules. A verbose dependency tree reveals the selected and omitted versions. Align them through one managed property or the framework's supported upgrade path. Do not scatter exclusions until the tree looks visually shorter. Each exclusion should answer which direct dependency now supplies that module and why its version is compatible.

Third-party browser libraries can touch DevTools without the test source importing a versioned package. A tracing plugin, authentication helper, network stub, or performance collector may call getDevTools during setup. If the warning appears in suites that look like classic WebDriver, capture the first application stack above Selenium and temporarily disable one integration at a time. The evidence is a warning that disappears with the component and a product smoke that still runs. Muting the logger would hide the dependency without removing it.

Remote execution adds two version inventories. The Java client owns the generated models it loads. The Grid node owns the browser and driver, and the Grid path carries the DevTools or BiDi connection. Record both client and Grid releases, but do not assume upgrading the server supplies missing classes to the client process. Conversely, a current client cannot repair an old Grid path that does not expose or forward the required connection. A local success plus remote failure is a reason to compare capabilities and connection setup, not to add another local JAR blindly.

Feature probes also uncover semantic drift that an exact-major assertion cannot. A network listener may connect but miss an event because subscription timing changed, the test navigated before the handler was installed, or the chosen page served from a different context. Register the handler first, navigate an owned page, filter for an identifying URL or request field, and bound the wait. Preserve any events that did arrive. Zero events suggests connection or subscription; unrelated events suggest the filter or page; a matching request with a changed response shape suggests model semantics.

Treat removal of a warning as one checkpoint in the upgrade, not the acceptance result. Re-run a negative product assertion that depends on the feature. For a request-blocking test, prove the forbidden destination did not receive the request and the page observed the expected failure state. For console capture, deliberately emit one known error and assert its identifying text. For emulation, assert a page-visible consequence rather than a successful command return.

Rollback criteria should be decided before promotion. Roll back the browser image if the required model has not shipped and the pinned image remains acceptable under the organization's security policy. Roll back Selenium if the new client breaks broader WebDriver coverage and the old browser-client pair remains supported. Keep the upgrade and disable an obsolete CDP helper if its diagnostic value is lower than its coupling cost. Each choice protects a different risk, so an automatic “use latest everything” rule is not an incident plan.

Keep browser drift visible in CI

Choose whether the job follows a browser channel or a fixed image. A channel-following canary gives early warning when Chrome advances beyond the Selenium release. A fixed release job gives reproducibility for merge gating. Many teams need both: the fixed job blocks changes, while a scheduled canary opens an infrastructure alert before the next image refresh.

The workflow below records runtime facts, verifies the resolved Selenium modules, runs ordinary WebDriver smoke coverage, and then applies the exact CDP gate. It does not grep a fabricated error string. If the browser advances, ExactCdpBindingTest fails on actual selected majors.

YAML
name: selenium-protocol-compatibility

on:
  pull_request:
  schedule:
    - cron: "23 3 * * *"

jobs:
  chrome-and-selenium:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    env:
      BIDI_SMOKE_URL: ${{ vars.BIDI_SMOKE_URL }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: "21"
          cache: maven
      - name: Record Chrome and Selenium dependencies
        run: |
          google-chrome --version
          ./mvnw -B dependency:tree -Dincludes=org.seleniumhq.selenium
      - name: Prove classic WebDriver still works
        run: ./mvnw -B -Dtest=WebDriverSmokeTest test
      - name: Require the CDP model used by this suite
        run: ./mvnw -B -Dtest=ExactCdpBindingTest test
      - name: Prove the BiDi migration path
        run: ./mvnw -B -Dtest=BidiNetworkSmokeTest test

On Grid, record the returned browser capability from the allocated node. The Chrome binary installed on the GitHub runner is irrelevant when the browser runs elsewhere. Tag node images with browser, driver, and Selenium server versions, then include the tag in the test report.

Roll an upgrade through one node pool first. Run the WebDriver smoke, exact binding gate, and feature probe against that pool. Then run representative product tests that use the adapter. Expand only after the evidence is clean. Keeping old and new pools available for a short window makes rollback possible, but route selection must be visible so tests do not silently land on either.

Do not fail every suite on this warning when no test uses CDP. That policy creates upgrade pressure without protecting a product claim. Keep one informational inventory check, remove unused DevTools dependencies, and schedule the Selenium upgrade normally. If a team later adds CDP use, code review should require the compatibility probe at the same time.

Do not suppress the warning while a nearest binding drives a release-critical feature. Silence makes the next failure harder to connect to browser drift. Align or pin first, then decide whether reduced log noise is worth a narrowly scoped logger rule.

Finally, do not claim success because the warning disappeared. A logging configuration can make that happen. The meaningful finish is an aligned dependency tree, a browser version recorded from the real session, and a functional probe that observes the command or event the suite depends on.

// FIELD DISPATCH

Get the QA Field Notes

Weekly QA battles, AI testing guides, and interview drills. Free on Substack.

// LIVE COURSE / THE TESTING ACADEMY

Playwright Automation Mastery

Go beyond Selenium. Master Playwright with JS/TS in 90 days.

From the instructor behind this guide.

Playwright jobs are growing 8x faster than Selenium. 90 days / 75+ live hrs / Tue-Thu-Sat 7 AM IST.

Code PROMODE / 10% offJoin the batch

The Testing Academy editorial desk

Practical QA guidance built around test evidence, production tradeoffs, and interview-ready explanations.

Published July 25, 2026 / Reviewed August 4, 2026

PRIMARY REFERENCES

Verify the details at the source

QABattle guides are practical explanations. Product behavior, standards, and APIs can change, so use these primary references for the canonical details.

  1. 01
    Official selenium.dev reference

    selenium.dev

    Primary documentation selected and verified for the claims in this guide.

  2. 02
    Official selenium.dev reference

    selenium.dev

    Primary documentation selected and verified for the claims in this guide.

  3. 03
    Official selenium.dev reference

    selenium.dev

    Primary documentation selected and verified for the claims in this guide.

  4. 04
    Official selenium.dev reference

    selenium.dev

    Primary documentation selected and verified for the claims in this guide.

FAQ / QUICK ANSWERS

Questions testers ask

Why does Selenium say it cannot find an exact CDP match?

The Java binding has identified the Chromium major version but does not have an exact generated CDP implementation for it on the runtime classpath. The warning states whether Selenium selected a nearby implementation or found none.

Will a CDP mismatch break normal WebDriver clicks and navigation?

Not by itself. Classic WebDriver commands use the WebDriver protocol, so prove a failing command and do not blame a DevTools warning that merely appears earlier in the log.

Should I add a selenium-devtools-vNN dependency manually?

Only after confirming that the artifact exists for your Selenium release and that your project intentionally manages those modules. Most projects using `selenium-java` should first upgrade and align the Selenium dependency set.

Why does DevTools work in the IDE but fail in the packaged JAR?

A packaged application can omit runtime dependencies or merge service-provider files incorrectly. Compare the IDE and packaged classpaths, then inspect the JAR for Selenium's CDP service metadata.

Can I suppress the CdpVersionFinder warning?

You can filter logging after you establish that no test uses the affected feature, but suppression does not add protocol support. Keep a compatibility smoke test so a future CDP use cannot arrive unnoticed.