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
- Run `codewhale dsh update` to refresh the overlay and receipt hash, then retry install-bundle.
- If you intentionally edited the overlay, re-run connect/update so the recorded hash matches before installing the bundle.
- 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
- Never hand-edit the overlay file; use documented flags.
- Re-run connect/update after any tool or sync process touches the overlay.
- Verify the overlay hash before scripted bundle installs.
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
- bundle already installed; use
- DSH is not connected; run
- DSH plugin path not available
- Source changed; refresh the import preview
- the ` ` profile carries identity only after ` install-bundle
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)