multica-ai/multica · error
link memories to store %s: %w
Error message
link memories to store %s: %w
What it means
Returned by mountHermesMemories when createDirLink fails to link the overlay's memories/ path to the agent-scoped store. This link is the whole point of the mount — without it the agent's memory is task-local again — so failure aborts the overlay.
Source
Thrown at server/internal/daemon/execenv/hermes_memory.go:178
// Runs before the store dir is created, so migration can publish a
// fully-copied tree with one atomic rename. Fails closed: the source
// dir below is only removed once every entry is safely in the store.
if err := migrateHermesTaskMemories(dst, storeDir, logger); err != nil {
return err
}
}
if err := os.RemoveAll(dst); err != nil {
return fmt.Errorf("remove stale memories path %s: %w", dst, err)
}
} else if !os.IsNotExist(err) {
return fmt.Errorf("stat memories path %s: %w", dst, err)
}
if err := os.MkdirAll(storeDir, 0o700); err != nil {
return fmt.Errorf("create hermes memory store %s: %w", storeDir, err)
}
if err := createDirLink(storeDir, dst); err != nil {
return fmt.Errorf("link memories to store %s: %w", storeDir, err)
}
// Stamp the store as just-used: mounting it does not touch its mtime, so
// without this the GC's idle check could reclaim a long-idle agent's memory
// right as a task picks it back up.
touchHermesMemoryStore(storeDir, logger)
return nil
}
// migrateHermesTaskMemories copies the contents of a pre-existing task-local
// memories dir into an empty store, so upgrading a daemon does not drop what an
// in-flight task had already remembered.
//
// The caller removes the source directory as soon as this returns nil, so
// "nil" has to mean "the source is safe to delete" and nothing else. Three
// rules follow from that:
//
// - It copies rather than moves. A move is faster but fails across
// filesystems — the workspaces root and the Multica profile dir can be onView on GitHub (pinned to 2c0912b6ec)
Solutions
- Check the wrapped error: ERROR_ALREADY_EXISTS / EEXIST → a race with another task; retry the task once the other finishes.
- On Windows, keep the Multica profile dir and task overlays on the same volume as each other.
- If symlinks are disabled by policy (Windows Developer Mode off, non-admin), enable them or run the daemon with the privilege to create junctions.
Defensive patterns
Strategy: validation
Validate before calling
// Verify linkability beforehand: target exists and dst is linkable.
if err := os.MkdirAll(storeDir, 0o700); err == nil {
if _, err := os.Lstat(dst); err == nil {
// expect the mount to replace it; if this fails at runtime, check perms
}
} Try / catch
if err := mountHermesMemories(home, store, logger); err != nil && strings.Contains(err.Error(), "link memories to store") {
// EEXIST from a racing task: safe to re-invoke once after the race settles
err = mountHermesMemories(home, store, logger)
} Prevention
- On Windows keep profile dir and overlays on one volume
- Enable symlink/junction privilege for the daemon user
- Avoid launching duplicate tasks that share one overlay home
When it happens
Trigger: createDirLink fails to create the store→overlay symlink/junction: the overlay memories path was removed by a racing task between Lstat and link, a symlink already exists at dst, or (Windows) directory junction creation is denied because the target is on another volume or privileges are missing.
Common situations: Two concurrent tasks for the same agent mounting the same overlay home; running on Windows without the rights to create junctions/symlinks when the store is on a different drive; security software reverting symlinks under the overlay.
Related errors
- mirror %s: %w
- remove stale %s: %w
- clear empty hermes store %s before publishing: %w
- reconcile stale %s: %w
- remove legacy task state %s: %w
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/4f38e1c1c5569f99.
Report an issue: GitHub.