Hmbown/CodeWhale · error · anyhow::Error

DSH is not connected; nothing to remove

Error message

DSH is not connected; nothing to remove

What it means

Removing the installed DSH bundle requires a 'current' connection record in the DSH receipt document. When the receipt has no current record — meaning DSH was never connected or the connection was already removed — this anyhow::bail! aborts the removal flow before touching the profile or bundle files.

Solutions

  1. Check connection state first with the DSH status/connect flow before attempting removal
  2. Only run the remove command after a successful `codewhale dsh connect`
  3. If you believe DSH is connected, inspect the receipt file at the DshPaths.receipt location and re-run connect to repopulate the current record

Example fix

// before
remove_bundle(paths, detection, runner)?; // bails when not connected
// after
if dsh_is_connected(&paths)? {
    remove_bundle(paths, detection, runner)?;
}
Defensive patterns

Strategy: validation

Validate before calling

if !std::path::Path::new(&paths.receipt).exists() { eprintln!("DSH not connected; run connect first"); return; }

Try / catch

match remove_bundle_result { Err(e) if e.to_string().contains("not connected") => { /* treat as no-op */ }, Err(e) => return Err(e), Ok(removed) => { /* use removed */ } }

Prevention

When it happens

Trigger: Calling the DSH disconnect/remove flow (e.g. `codewhale dsh disconnect`) when `doc.current` is None: DSH was never connected in this workspace, the receipt file is missing (load creates an empty document), or a prior removal already took the current record.

Common situations: Running disconnect twice; deleting or resetting the DSH receipt file while assuming a connection still exists; a fresh checkout or new workspace where setup was never run.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/35f0e4e0c88b083e. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/integrations/dsh/mod.rs:887

            "bundle_dir": paths.bundle_dir.display().to_string(),
            "patch_sha256": bundle_record.patch_sha256,
            "app_bundle": app.package_name(),
        }),
    );
    Ok(bundle_record)
}

/// `dsh plugin --profile codewhale remove codewhale-dsh-bundle`, then delete
/// only the Codewhale-owned bundle files. The DSH profile directory (and the
/// app bundle link dsh recorded there) is DSH-owned and is left in place.
pub(crate) fn remove_bundle(
    paths: &DshPaths,
    detection: &DshDetection,
    runner: &dyn DshRunner,
) -> Result<Vec<PathBuf>> {
    let mut doc = DshReceiptDocument::load(&paths.receipt)?;
    let Some(mut record) = doc.current.take() else {
        anyhow::bail!("DSH is not connected; nothing to remove");
    };
    let Some(bundle_record) = record.bundle.take() else {
        anyhow::bail!("no bundle is installed");
    };
    let outcome = bundle::remove_from_profile(runner, detection)?;
    let removed = bundle::remove_bundle_files(&paths.bundle_dir)?;
    let now = now_rfc3339();
    record.updated_at = now.clone();
    doc.push(DshReceiptEntry {
        event: DshReceiptEvent::RemoveBundle,
        at: now,
        codewhale_version: codewhale_version(),
        dsh_version: detection.version.clone(),
        dsh_home: detection.dsh_home.clone(),
        overlay_sha256: Some(record.overlay_sha256.clone()),
        skin_sha256: record.skin_sha256.clone(),
        identity_summary: Some(identity_summary(&record.identity)),
        permission_mode: Some(record.identity.permission_mode.as_str().to_string()),

View on GitHub (pinned to 73e0f67d83)