Hmbown/CodeWhale · error · anyhow::Error

overlay is stale; run

Error message

overlay is stale; run `{CLI_COMMAND} update` before install-bundle

What it means

install_bundle verifies that the overlay file on disk still matches the sha256 recorded in the receipt at connect time. If the file's hash differs from record.overlay_sha256, the overlay has drifted (edited, regenerated, or replaced) and installing the bundle on top of a stale overlay would bake the wrong content into the profile, so it aborts and asks for `update` first.

Solutions

  1. Run `codewhale dsh update` to refresh the overlay and receipt hash, then retry install-bundle.
  2. If you intentionally edited the overlay, re-run connect/update so the recorded hash matches before installing the bundle.
  3. Avoid hand-editing the overlay; use documented flags (`--skin`, ocean options) instead.

Example fix

// before
vim ~/.codewhale/dsh/overlay.css
codewhale dsh install-bundle  # Error: overlay is stale

// after
codewhale dsh update
codewhale dsh install-bundle
Defensive patterns

Strategy: validation

Validate before calling

let status = codewhale_dsh_status()?;
let overlay = std::fs::read_to_string(&status.overlay_path)?;
if sha256_hex(overlay.as_bytes()) != status.record.as_ref().unwrap().overlay_sha256 {
    eprintln!("overlay drifted; run `codewhale dsh update` first");
    return Err(...);
}

Try / catch

match install_bundle(&paths, &detection, runner, &availability, app) {
    Err(e) if e.to_string().contains("overlay is stale") => {
        run_dsh_update()?;
        install_bundle(&paths, &detection, runner, &availability, app)?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `codewhale dsh install-bundle` after the overlay file at paths.overlay was modified since the last `codewhale dsh connect`/`update` — manual edits, an older Codewhale rewriting it, or sync tools reverting it.

Common situations: Hand-editing the overlay to tweak settings; running install-bundle after a Codewhale upgrade regenerated the overlay; restoring the overlay from a backup with different content.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

    app: DshAppBundle,
) -> Result<DshBundleRecord> {
    let pnpm_version = match availability {
        BundleAvailability::Available { pnpm_version } => pnpm_version.clone(),
        BundleAvailability::NotAvailable { reason } => {
            anyhow::bail!("DSH plugin path not available: {reason}")
        }
    };
    let mut doc = DshReceiptDocument::load(&paths.receipt)?;
    let Some(mut record) = doc.current.take() else {
        anyhow::bail!("DSH is not connected; run `{CLI_COMMAND} connect` first");
    };
    if record.bundle.is_some() {
        anyhow::bail!("bundle already installed; use `{CLI_COMMAND} update` or `remove-bundle`");
    }
    let overlay_text = std::fs::read_to_string(&paths.overlay)
        .with_context(|| format!("read {}", paths.overlay.display()))?;
    if sha256_hex(overlay_text.as_bytes()) != record.overlay_sha256 {
        anyhow::bail!("overlay is stale; run `{CLI_COMMAND} update` before install-bundle");
    }
    // install-bundle defaults the palette on; `update --skin false` is the
    // off switch. `connect --skin` records the same decision for a later update.
    let skin = true;
    // The ocean scene follows the recorded decision (default on).
    let ocean = record.ocean_enabled;
    let patch_sha = bundle::write_bundle(
        &paths.bundle_dir,
        &codewhale_version(),
        &overlay_text,
        skin,
        ocean,
    )?;
    let (app_source, outcomes) =
        match bundle::install_into_profile(runner, detection, app, &paths.bundle_dir) {
            Ok(ok) => ok,
            Err(error) => {
                // Leave DSH state as dsh left it; drop our half-written package.

View on GitHub (pinned to 73e0f67d83)