{"record":{"id":"577e95d604df0875","repo":"rwf2/Rocket","slug":"create-tokio-runtime-577e95","errorCode":null,"errorMessage":"create tokio runtime","messagePattern":"create tokio runtime","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/lib/src/local/blocking/client.rs","lineNumber":39,"sourceCode":"/// let rocket = rocket::build();\n/// let client = Client::tracked(rocket).expect(\"valid rocket\");\n/// let response = client.post(\"/\")\n///     .body(\"Hello, world!\")\n///     .dispatch();\n/// ```\npub struct Client {\n    pub(crate) inner: Option<asynchronous::Client>,\n    runtime: RefCell<tokio::runtime::Runtime>,\n}\n\nimpl Client {\n    fn _new<P: Phase>(rocket: Rocket<P>, tracked: bool, secure: bool) -> Result<Client, Error> {\n        let runtime = tokio::runtime::Builder::new_multi_thread()\n            .thread_name(\"rocket-local-client-worker-thread\")\n            .worker_threads(1)\n            .enable_all()\n            .build()\n            .expect(\"create tokio runtime\");\n\n        // Initialize the Rocket instance\n        let inner = Some(runtime.block_on(asynchronous::Client::_new(rocket, tracked, secure))?);\n        Ok(Self { inner, runtime: RefCell::new(runtime) })\n    }\n\n    // WARNING: This is unstable! Do not use this method outside of Rocket!\n    #[doc(hidden)]\n    pub fn _test<T, F>(f: F) -> T\n        where F: FnOnce(&Self, LocalRequest<'_>, LocalResponse<'_>) -> T + Send\n    {\n        let client = Client::debug(crate::build()).unwrap();\n        let request = client.get(\"/\");\n        let response = request.clone().dispatch();\n        f(&client, request, response)\n    }\n\n    #[inline(always)]","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/rwf2/Rocket/blob/3a54d079aef060a8f732bd04ea54b0581a604087/core/lib/src/local/blocking/client.rs#L21-L57","documentation":"rocket::local::blocking::Client runs requests on its own private multi-thread tokio runtime (one worker thread) built inside Client::_new; the .expect(\"create tokio runtime\") panics if Builder::build() returns an error. Build errors come from the environment: thread spawn failure (pid/thread limit reached, thread-stack memory exhausted) or I/O-driver fd creation failure (fd limit reached, seccomp blocking epoll). Because every Client constructs a fresh runtime, large parallel test suites multiply runtime creation and can exhaust limits even when each individual test passes.","triggerScenarios":"Calling Client::tracked(rocket), Client::untracked(rocket), or Client::debug(rocket) — all route through _new — when the test process is out of thread or fd budget; classically a large cargo test suite in a pids-limited container where each parallel test creates one more runtime with its own threads; EMFILE from leaked sockets/files leaving no descriptor for epoll/eventfd; seccomp/gVisor sandboxes in CI blocking the clone or epoll syscalls the runtime needs.","commonSituations":"Dockerized CI where cargo test defaults to high parallelism and hits --pids-limit; macOS/Linux dev machines or runners with low ulimit -u or ulimit -n during long test runs; leaked file descriptors in the code under test; tests mixing #[tokio::test] with the blocking client, which stresses the same resource budget; sandboxed CI executors.","solutions":["Cap test parallelism: run cargo test -- --test-threads=8 (or lower) so fewer runtimes exist at the same time.","Raise the limits in the test environment: Docker --pids-limit, cgroup pids.max, ulimit -u and ulimit -n.","Serialize runtime-heavy tests with a global Mutex guard so clients/runtimes are created one at a time, and construct one Client per test rather than per request.","Inside async harnesses (#[tokio::test] or #[rocket::test]) use rocket::local::asynchronous::Client instead of the blocking client.","Fix fd leaks (unclosed files/sockets) so descriptors remain available for epoll/eventfd."],"exampleFix":"// before — each parallel test builds its own tokio runtime; under a\n// pids-limited CI container the last tests panic: 'create tokio runtime'\n#[test]\nfn list_users() {\n    let client = Client::tracked(rocket()).unwrap();\n    assert_eq!(client.get(\"/users\").dispatch().status(), Status::Ok);\n}\n\n// after — serialize client construction (and run cargo test with\n// `--test-threads=8` plus a higher --pids-limit in CI)\nuse std::sync::Mutex;\nstatic CLIENT_LOCK: Mutex<()> = Mutex::new(());\n\n#[test]\nfn list_users() {\n    let _guard = CLIENT_LOCK.lock().unwrap();\n    let client = Client::tracked(rocket()).unwrap();\n    assert_eq!(client.get(\"/users\").dispatch().status(), Status::Ok);\n}","handlingStrategy":"validation","validationCode":"fn can_build_runtime() -> bool {\n    // probe exactly what Client::_new does: build a throwaway runtime\n    tokio::runtime::Builder::new_multi_thread()\n        .worker_threads(1)\n        .enable_all()\n        .build()\n        .is_ok()\n}\n\n// in the test harness before constructing blocking clients:\nif !can_build_runtime() {\n    eprintln!(\"skipping: no thread/fd budget for another tokio runtime\");\n    return;\n}","typeGuard":null,"tryCatchPattern":"use std::panic::AssertUnwindSafe;\n\nlet client = std::panic::catch_unwind(AssertUnwindSafe(|| {\n    Client::tracked(rocket())\n}));\nmatch client {\n    Ok(c) => { /* proceed with requests */ }\n    Err(_) => panic!(\n        \"environment cannot create a tokio runtime: check pids/fd limits\"\n    ),\n}","preventionTips":["Cap cargo test parallelism (--test-threads) in pids-limited CI containers","Raise --pids-limit, ulimit -u and ulimit -n in CI images","Construct one Client per test, never inside request loops","Use rocket::local::asynchronous::Client inside async test harnesses","Fix fd leaks — each new runtime needs spare descriptors for epoll/eventfd"],"tags":["rust","rocket","tokio","testing","local-client","panic","resource-limits"],"backgroundTag":"tokio-runtime-creation-failed","analyzedSha":"3a54d079aef060a8f732bd04ea54b0581a604087","analyzedAt":"2026-08-16T22:01:48.395Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}