{"record":{"id":"a7070386d9f94580","repo":"juspay/hyperswitch","slug":"spawn-block-failure","errorCode":null,"errorMessage":"Spawn block failure","messagePattern":"Spawn block failure","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/redis_interface/src/test.rs","lineNumber":2358,"sourceCode":"            let Some(pool) = get_auth_pool_or_skip().await else {\n                tracing::warn!(\"SKIP: auth test skipped — set TEST_REDIS_AUTH_PASSWORD to enable\");\n                return true;\n            };\n\n            let key: RedisKey = format!(\"test_auth_set_get_{}\", unique_test_id()).into();\n            let value = \"authenticated_value\".to_string();\n\n            let set_result = pool.set_key_with_expiry(&key, value.clone(), 60).await;\n            let get_result: Result<String, _> = pool.get_key(&key).await;\n            let del_result = pool.delete_key(&key).await;\n\n            set_result.is_ok()\n                && matches!(get_result, Ok(retrieved) if retrieved == value)\n                && del_result.is_ok()\n        })\n    })\n    .await\n    .expect(\"Spawn block failure\");\n\n    assert!(is_success);\n}\n\n#[tokio::test]\nasync fn test_authenticated_connection_pubsub() {\n    let is_success = tokio::task::spawn_blocking(move || {\n        futures::executor::block_on(async {\n            let Some(pool) = get_auth_pool_or_skip().await else {\n                tracing::warn!(\"SKIP: auth test skipped — set TEST_REDIS_AUTH_PASSWORD to enable\");\n                return true;\n            };\n\n            let channel = format!(\"test_auth_pubsub_{}\", unique_test_id());\n            let test_message = \"authenticated_message\";\n\n            pool.redis_conn\n                .subscriber","sourceCodeStart":2340,"sourceCodeEnd":2376,"githubUrl":"https://github.com/juspay/hyperswitch/blob/afd92843521ced2c6856b98ae4ea332e75102d88/crates/redis_interface/src/test.rs#L2340-L2376","documentation":"Panic message from .expect() on the JoinHandle of a tokio::task::spawn_blocking call in test_authenticated_connection_set_get (crates/redis_interface/src/test.rs:2358). The spawned blocking closure runs set/get/del round-trips; .await.unwrap-style expect fails either if the task panicked inside (e.g. an inner expect on a Redis op) or if the JoinError is a cancel/panic. The inner Redis failures are surfaced as this generic 'Spawn block failure'.","triggerScenarios":"spawn_blocking(...).await.expect(\"Spawn block failure\") returns Err: the closure panicked (unwrap/expect inside on set/get/del results, connection pool gone), or the runtime shut down the task (blocking pool saturated, runtime dropped).","commonSituations":"Redis not available so inner expects panic, propagating as JoinError::is_panic; test runtime torn down before the blocking task completes; too many blocking tasks starving the pool in parallel test runs.","solutions":["Fix the root cause inside the closure: run the test with a reachable Redis so set/get/del succeed instead of panicking.","Replace inner .expect()s in the closure with a Result-returning closure so failures surface as assertion messages, not JoinError panics.","Log the JoinError kind before asserting to distinguish panic vs cancel: expect(...) with a formatted message including err.is_panic().","Ensure the tokio runtime outlives the task (no missing .await, no early return) so the blocking task is not cancelled."],"exampleFix":"// before\nlet is_success = tokio::task::spawn_blocking(move || {\n    ...set_result.is_ok() && ...\n})\n.await\n.expect(\"Spawn block failure\");\n// after\nlet is_success = tokio::task::spawn_blocking(move || {\n    ...set_result.is_ok() && ...\n})\n.await\n.unwrap_or_else(|e| panic!(\"Spawn block failure (panic={})\", e.is_panic()));","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let is_success = tokio::task::spawn_blocking(move || { ... })\n    .await\n    .unwrap_or_else(|e| panic!(\"Spawn block failure (is_panic={}, cancelled={})\", e.is_panic(), e.is_cancelled()));","preventionTips":["Never expect()/unwrap() inside spawn_blocking closures; return Result or bool","Format JoinError details in the outer expect to expose the inner panic message","Ensure the tokio runtime outlives spawned blocking tasks","Confirm Redis availability first so inner operations don't panic"],"tags":["tokio","spawn-blocking","join-error","test-infrastructure","panic"],"backgroundTag":"thread-interrupted","analyzedSha":"afd92843521ced2c6856b98ae4ea332e75102d88","analyzedAt":"2026-09-18T01:18:02.947Z","contentChangedAt":"2026-09-18T01:18:02.947Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}