multica-ai/multica · error

read task-local hermes memories %s: %w

Error message

read task-local hermes memories %s: %w

What it means

Returned by migrateHermesTaskMemories when os.ReadDir on the task-local memories source dir fails. The migration cannot know which entries to copy, and skipping would mean silently dropping the agent's remembered context, so the overlay mount aborts.

Source

Thrown at server/internal/daemon/execenv/hermes_memory.go:222

//     half-populated store. First writer wins; the loser discards its staging
//     and takes the winner's store, which is the same outcome as finding a
//     store that was already populated.
//
// Only an absent or empty store is migrated into, so an upgrade never
// overwrites memory the agent has already accumulated.
func migrateHermesTaskMemories(taskDir, storeDir string, logger *slog.Logger) error {
	stored, err := os.ReadDir(storeDir)
	switch {
	case err == nil && len(stored) > 0:
		return nil // store already holds this agent's memory — never overwrite it
	case err != nil && !os.IsNotExist(err):
		// Treating this as "nothing to migrate" would delete the source below.
		return fmt.Errorf("read hermes memory store %s: %w", storeDir, err)
	}

	entries, err := os.ReadDir(taskDir)
	if err != nil {
		return fmt.Errorf("read task-local hermes memories %s: %w", taskDir, err)
	}
	if len(entries) == 0 {
		return nil
	}

	staging, err := newHermesStoreStaging(storeDir)
	if err != nil {
		return err
	}
	defer os.RemoveAll(staging) // no-op once the staging dir has been promoted

	for _, entry := range entries {
		src := filepath.Join(taskDir, entry.Name())
		if err := copyHermesMemoryEntry(src, filepath.Join(staging, entry.Name()), entry); err != nil {
			return fmt.Errorf("migrate task-local hermes memory %s into %s: %w", src, storeDir, err)
		}
	}

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Fix permissions on the task-local memories dir or re-run the task under the user that owns the overlay.
  2. If the task overlay is disposable, delete the whole task home so it is rebuilt without a legacy memories dir.
  3. Inspect the wrapped errno for hardware/mount errors before retrying.
Defensive patterns

Strategy: validation

Validate before calling

if ents, err := os.ReadDir(taskDir); err != nil {
    return fmt.Errorf("task memories unreadable, fix or clear %s: %w", taskDir, err)
} else if len(ents) == 0 {
    // migration is a no-op; safe to proceed
}

Prevention

When it happens

Trigger: os.ReadDir(<task-hermes-home>/memories) fails with EACCES (dir not readable by daemon user), EIO, or the path exists as something unreadable even though Lstat called it a directory earlier.

Common situations: Task overlay dirs written by a root-run daemon then read by a user-run daemon; corrupted overlay after a crash; FS-level errors on the volume backing task homes.

Related errors


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