libnyanpasu/clash-nyanpasu · critical

should never drop oneshot tx

Error message

should never drop oneshot tx

What it means

`load_imported_module` fetches module content over an internal oneshot channel spawned on an async runtime and does `rx.await.expect("should never drop oneshot tx")`. If the spawned task panics or the runtime is shut down before sending, the sender drops and the expect panics with this message.

Source

Thrown at backend/boa_utils/src/module/http.rs:177

                    let mime = response
                        .headers()
                        .get(reqwest::header::CONTENT_TYPE)
                        .and_then(|v| v.to_str().ok())
                        .map(|v| v.to_string())
                        .unwrap_or(mime::TEXT_PLAIN.to_string());
                    let body = response.text().await?;

                    log::debug!("finished fetching `{fetcher_url}`");
                    Ok(CachedItem {
                        mime,
                        content: body,
                    })
                }
                .await;
                let _ = tx.send(result);
            });
            rx.await.expect("should never drop oneshot tx")
        };

        if let Ok(item) = &item {
            match postcard::to_stdvec(&item) {
                Ok(item) => {
                    if let Err(err) = async_fs::write(&cache_path, &item).await {
                        log::error!(
                            "failed to write cache for `{url}`; path: `{}`. error: `{}`",
                            cache_path.display(),
                            err
                        );
                    }
                }
                Err(err) => {
                    log::error!("failed to serialize content: {err}");
                }
            }
        }

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Replace `.expect` with graceful handling: `rx.await.unwrap_or_else(|_| Err(...))` returning a JS error.
  2. Ensure the async runtime outlives all module-loading operations.
  3. Fix the root panic in the spawned task (often the invalid-url panic) so the sender always sends.
  4. Wrap module loading so runtime shutdown doesn't race pending imports.

Example fix

// before
rx.await.expect("should never drop oneshot tx")
// after
rx.await.map_err(|_| JsNativeError::typ().with_message("module loader task dropped"))?
Defensive patterns

Strategy: try-catch

Validate before calling

// cannot pre-validate; ensure runtime is alive before loading modules
if (!runtimeAlive()) throw new Error('async runtime unavailable; cannot load modules');

Try / catch

// Rust side: replace expect with graceful JS error
rx.await.map_err(|_| JsNativeError::typ().with_message("module loader task dropped"))?

Prevention

When it happens

Trigger: Calling `load_imported_module` when the spawned fetch task panics (e.g. the invalid-url panic in the same flow), the async runtime has been dropped, or the task is cancelled before `tx.send` runs.

Common situations: Runtime shutdown during app exit while a module import is in flight; a panic inside the spawned task (like error 238) dropping the oneshot sender; blocking the runtime so the task is aborted.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/87308071719af4d0. Report an issue: GitHub.