{"record":{"id":"4f38e1c1c5569f99","repo":"multica-ai/multica","slug":"link-memories-to-store-s-w","errorCode":null,"errorMessage":"link memories to store %s: %w","messagePattern":"link memories to store (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/daemon/execenv/hermes_memory.go","lineNumber":178,"sourceCode":"\t\t\t// Runs before the store dir is created, so migration can publish a\n\t\t\t// fully-copied tree with one atomic rename. Fails closed: the source\n\t\t\t// dir below is only removed once every entry is safely in the store.\n\t\t\tif err := migrateHermesTaskMemories(dst, storeDir, logger); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := os.RemoveAll(dst); err != nil {\n\t\t\treturn fmt.Errorf(\"remove stale memories path %s: %w\", dst, err)\n\t\t}\n\t} else if !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"stat memories path %s: %w\", dst, err)\n\t}\n\n\tif err := os.MkdirAll(storeDir, 0o700); err != nil {\n\t\treturn fmt.Errorf(\"create hermes memory store %s: %w\", storeDir, err)\n\t}\n\tif err := createDirLink(storeDir, dst); err != nil {\n\t\treturn fmt.Errorf(\"link memories to store %s: %w\", storeDir, err)\n\t}\n\t// Stamp the store as just-used: mounting it does not touch its mtime, so\n\t// without this the GC's idle check could reclaim a long-idle agent's memory\n\t// right as a task picks it back up.\n\ttouchHermesMemoryStore(storeDir, logger)\n\treturn nil\n}\n\n// migrateHermesTaskMemories copies the contents of a pre-existing task-local\n// memories dir into an empty store, so upgrading a daemon does not drop what an\n// in-flight task had already remembered.\n//\n// The caller removes the source directory as soon as this returns nil, so\n// \"nil\" has to mean \"the source is safe to delete\" and nothing else. Three\n// rules follow from that:\n//\n//   - It copies rather than moves. A move is faster but fails across\n//     filesystems — the workspaces root and the Multica profile dir can be on","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/daemon/execenv/hermes_memory.go#L160-L196","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Verify linkability beforehand: target exists and dst is linkable.\nif err := os.MkdirAll(storeDir, 0o700); err == nil {\n    if _, err := os.Lstat(dst); err == nil {\n        // expect the mount to replace it; if this fails at runtime, check perms\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := mountHermesMemories(home, store, logger); err != nil && strings.Contains(err.Error(), \"link memories to store\") {\n    // EEXIST from a racing task: safe to re-invoke once after the race settles\n    err = mountHermesMemories(home, store, logger)\n}","preventionTips":["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"],"tags":["filesystem","symlink","hermes","windows","race-condition"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}