GoogleChromeLabs / GoogleChromeLabs/chrome-for-testing

Starting a session fails due to user data directory

Open
#189 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
1.3k
Forks
159
Avg merge
18h 37m
Merged PRs (30d)
3

Description

**Describe the bug**

A simple program attempting to connect to `chromedriver` fails to create a session.

This is following up from https://github.com/jonhoo/fantoccini/issues/301 since it doesn't appear related to this library but rather a lower level issue.

**To reproduce**

I have a simple Rust project which creates this behaviour.

Download `chrome` and `chromedriver` with:
```bash
# Install prerequisites
sudo apt install unzip

# Install chrome headerless (normal chrome also works but is slower)
wget https://storage.googleapis.com/chrome-for-testing-public/139.0.7258.154/linux64/chrome-headless-shell-linux64.zip
unzip chrome-headless-shell-linux64.zip
sudo mv chrome-headless-shell-linux64/chrome-headless-shell /usr/local/bin/chrome
sudo chmod +x /usr/local/bin/chrome

# Install ChromeDriver
wget https://storage.googleapis.com/chrome-for-testing-public/139.0.7258.154/linux64/chromedriver-linux64.zip
unzip chromedriver-linux64.zip
sudo mv chromedriver-linux64/chromedriver /usr/local/bin/chromedriver
sudo chmod +x /usr/local/bin/chromedriver
```

Then make sure you have Rust installed.

Run `cargo new --name hello-fantoccini` to create a new project.

Update the below files to match the contents below.

`main.rs`:
```rust
use reqwest::Url;
use std::{
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
time::Duration,
};

struct ChromeDriver(std::process::Child);
impl Drop for ChromeDriver {
fn drop(&mut self) {
self.0.kill().unwrap();
self.0.wait().unwrap();
}
}

#[tokio::main]
async fn main() {
let status = std::process::Command::new("chrome")
.arg("--version")
.output()
.unwrap();
assert!(
status.status.success(),
"Missing chrome installation `chrome --version`: {status:?}"
);
println!(
"chrome installed:\n\t{:?}\n\t{:?}",
std::str::from_utf8(&status.stdout),
std::str::from_utf8(&status.stderr)
);

let status = std::process::Command::new("chromedriver")
.arg("--version")
.output()
.unwrap();
assert!(
status.status.success(),
"Missing chromedriver installation `chromedriver --version`: {status:?}"
);
println!(
"chromedriver installed:\n\t{:?}\n\t{:?}",
std::str::from_utf8(&status.stdout),
std::str::from_utf8(&status.stderr)
);

let chromedriver_port = 4470;
let chromedriver = ChromeDriver(
std::process::Command::new("chromedriver")
.arg(format!("--port={chromedriver_port}"))
.spawn()
.unwrap(),
);
println!("chromedriver started");

const TIMEOUT: Duration = Duration::from_secs(30);
const SLEEP: Duration = Duration::from_millis(100);
let timeout = std::time::Instant::now();
let client = reqwest::Client::new();
let url = Url::parse(&format!(
"http://{}",
SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, chromedriver_port))
))
.unwrap();
loop {
assert!(timeout.elapsed() <= TIMEOUT, "timeout");
let response = client.get(url.join("/status").unwrap()).send().await;
match response {
Ok(res) if res.status().is_success() => break,
_ => {}
}
tokio::time::sleep(SLEEP).await;
}
println!("chromedriver running");

let user_data_dir = tempfile::tempdir().unwrap();
let user_data_arg = format!("--user-data-dir={}", user_data_dir.path().to_string_lossy());

let json = serde_json::json!({
"capabilities": {
"alwaysMatch": {
"browserName": "chrome",
"goog:chromeOptions": {
"binary": "/usr/local/bin/chrome",
"args": [
user_data_arg,
"--headless=new",
"--no-sandbox",
"--disable-dev-shm-usage"
]
}
},
"firstMatch": [{}]
}
});
let res = client
.post(url.join("/session").unwrap())
.json(&json)
.send()
.await
.unwrap();
println!("create session: {res:?}");
println!("create session: {:?}", res.text().await.unwrap());

drop(chromedriver);
drop(user_data_dir);
}
```

`cargo.toml`:
```toml
[package]
name = "hello-fantoccini"
version = "0.1.0"
edition = "2024"

[dependencies]
reqwest = { version = "0.12.7", features = ["cookies", "json", "stream", "multipart", "native-tls-vendored"] }
tokio = { version = "1.42.0", features = ["full"] }
serde_json = "1.0.143"
tempfile = "3.15.0"
```

Run with `cargo run`.

Which should produce an output like
```
chrome installed:
Ok("Google Chrome for Testing 139.0.7258.154\n")
Ok("")
chromedriver installed:
Ok("ChromeDriver 139.0.7258.154 (9e0d6b2b47ffb17007b713429c9a302f9e43847f-refs/branch-heads/7258@{#2926})\n")
Ok("")
chromedriver started
Starting ChromeDriver 139.0.7258.154 (9e0d6b2b47ffb17007b713429c9a302f9e43847f-refs/branch-heads/7258@{#2926}) on port 4470
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully on port 4470.
chromedriver running
create session: Response { url: "http://127.0.0.1:4470/session", status: 500, headers: {"content-length": "882", "content-type": "application/json; charset=utf-8", "cache-control": "no-cache"} }
create session: "{\"value\":{\"error\":\"session not created\",\"message\":\"session not created: probably user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir\",\"stacktrace\":\"#0 0x55ef0dce808a \\u003Cunknown>\\n#1 0x55ef0d787a70 \\u003Cunknown>\\n#2 0x55ef0d7c2e07 \\u003Cunknown>\\n#3 0x55ef0d7bd5a7 \\u003Cunknown>\\n#4 0x55ef0d80d93e \\u003Cunknown>\\n#5 0x55ef0d80cf06 \\u003Cunknown>\\n#6 0x55ef0d7ff1b3 \\u003Cunknown>\\n#7 0x55ef0d7cb59b \\u003Cunknown>\\n#8 0x55ef0d7cc971 \\u003Cunknown>\\n#9 0x55ef0dcad25b \\u003Cunknown>\\n#10 0x55ef0dcb0fa9 \\u003Cunknown>\\n#11 0x55ef0dc94339 \\u003Cunknown>\\n#12 0x55ef0dcb1b58 \\u003Cunknown>\\n#13 0x55ef0dc78c1f \\u003Cunknown>\\n#14 0x55ef0dcd5118 \\u003Cunknown>\\n#15 0x55ef0dcd52f6 \\u003Cunknown>\\n#16 0x55ef0dce7066 \\u003Cunknown>\\n#17 0x70813489caa4 \\u003Cunknown>\\n#18 0x708134929c3c \\u003Cunknown>\\n\"}}"
```

Removing `"goog:chromeOptions"` and re-running produce the same outcome.

`uname -a` outputs:
```
Linux DESKTOP-UTVQJHQ 6.6.87.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
```

**Expected behavior**
It should successfully create a new session.

Contributor guide

Open the contributing guide

Research direction

Start with the reproduction in main.rs and its dependencies in cargo.toml, then run cargo run in the stated WSL2 environment. Compare the ChromeDriver /session response with the expected successful session creation and determine whether the failure belongs to Chrome for Testing or the surrounding setup. Done means the supplied program creates a new session.

Written by the indexing model from the issue text.

Assessment

Tech stack
linux, rust
Domain
operating-systems, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.