multica-ai/multica · error

read overlay home: %w

Error message

read overlay home: %w

What it means

reconcileMirroredEntries could not list the task-local overlay home (os.ReadDir(hermesHome)) while pruning entries that are no longer mirrored from the shared home. The overlay directory itself is unreadable or was removed out from under the prepare step. The reconciliation exists so deleted-in-shared-home entries and Windows copy-fallback leftovers do not survive as stale state.

Source

Thrown at server/internal/daemon/execenv/hermes_home.go:551

			continue
		}
		src := filepath.Join(sharedHome, name)
		dst := filepath.Join(hermesHome, name)
		if err := linkSharedHermesEntry(src, dst); err != nil {
			return fmt.Errorf("mirror %s: %w", name, err)
		}
		mirrored[name] = struct{}{}
	}
	return reconcileMirroredEntries(hermesHome, mirrored)
}

// reconcileMirroredEntries removes overlay entries that are neither overlay-owned
// nor currently mirrored from the shared home, so a shared entry deleted between
// runs (or a Windows copy-fallback left behind) doesn't survive as stale state.
func reconcileMirroredEntries(hermesHome string, mirrored map[string]struct{}) error {
	entries, err := os.ReadDir(hermesHome)
	if err != nil {
		return fmt.Errorf("read overlay home: %w", err)
	}
	for _, entry := range entries {
		name := entry.Name()
		if isHermesOverlayOwnedEntry(name) {
			continue
		}
		if _, keep := mirrored[name]; keep {
			continue
		}
		if err := os.RemoveAll(filepath.Join(hermesHome, name)); err != nil {
			return fmt.Errorf("reconcile stale %s: %w", name, err)
		}
	}
	return nil
}

// prepareHermesTaskLocalState migrates an overlay built by an older daemon away
// from the shared Hermes SQLite session store. Without the marker, state.db and

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Check the overlay dir exists and is readable by the daemon user: `ls -la <envRoot>/hermes-home`.
  2. Delete the whole overlay dir and let the next prepare rebuild it from the shared home.
  3. Serialize env GC/teardown against task start so the overlay is not deleted mid-prepare.
  4. Check dmesp/logs for underlying I/O errors (read-only remount, disk failure) and remount/replace the volume.
Defensive patterns

Strategy: validation

Validate before calling

if fi, err := os.Stat(hermesHome); err != nil {
	return fmt.Errorf("overlay home missing before reconcile: %w", err)
} else if !fi.IsDir() || fi.Mode().Perm()&0o400 == 0 {
	return fmt.Errorf("overlay home not a readable dir: %s", hermesHome)
}

Try / catch

if err := reconcileMirroredEntries(hermesHome, mirrored); err != nil {
	if errors.Is(err, fs.ErrNotExist) {
		// overlay vanished (GC race): recreate from scratch instead of failing
		return mirrorSharedHermesHome(sharedHome, hermesHome, logger)
	}
	return err
}

Prevention

When it happens

Trigger: The generated overlay dir (env RootDir/hermes-home) has mode 000, was deleted concurrently (env teardown/GC racing a task start), or sits on a failing filesystem.

Common situations: Cloud GC loop wiping env dirs at the same moment a task starts; a previous crash left a partially-created overlay with wrong permissions; disk-full filesystem going read-only.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/1cbec38391355caa. Report an issue: GitHub.