{"record":{"id":"d7cdddda0701cda5","repo":"multica-ai/multica","slug":"remove-stale-memories-path-s-w","errorCode":null,"errorMessage":"remove stale memories path %s: %w","messagePattern":"remove stale memories path (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/daemon/execenv/hermes_memory.go","lineNumber":168,"sourceCode":"\tif fi, err := os.Lstat(dst); err == nil {\n\t\tif fi.Mode()&os.ModeSymlink != 0 {\n\t\t\tif target, rlErr := os.Readlink(dst); rlErr == nil && filepath.Clean(target) == filepath.Clean(storeDir) {\n\t\t\t\tif err := os.MkdirAll(storeDir, 0o700); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"create hermes memory store %s: %w\", storeDir, err)\n\t\t\t\t}\n\t\t\t\ttouchHermesMemoryStore(storeDir, logger)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t} else if fi.IsDir() {\n\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","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/daemon/execenv/hermes_memory.go#L150-L186","documentation":"Returned by mountHermesMemories when os.RemoveAll fails while deleting the overlay's task-local memories/ path after it was migrated (or found as a non-store symlink). The removal is the last step of repointing HERMES_HOME/memories at the agent-scoped persistent store, so failure means the mount cannot proceed and the task overlay build aborts.","triggerScenarios":"os.RemoveAll(dst) on <overlay-hermes-home>/memories fails: a file inside is held open with mandatory locking semantics, the directory or one of its children has read-only/0700-not-owner permissions, an antivirus or indexer on Windows holds a handle, or another concurrent task is writing into the same task-local memories dir mid-delete.","commonSituations":"Upgrading a daemon on a machine where a legacy real memories/ directory exists; running the daemon under a service account that lacks ownership of files written by an earlier user-run daemon; two tasks sharing one task dir racing on the same memories path.","solutions":["Check the wrapped error: EACCES/EPERM means permissions (chown or delete the stale dir manually), EBUSY/sharing-violation means a process holds it open (stop other tasks/daemons, retry).","Manually move the stale <task-home>/memories aside and re-run; the store migration already copied its contents, so nothing is lost.","Ensure only one daemon instance per Multica profile dir runs concurrently."],"exampleFix":"// before: stale dir blocks mount, task overlay fails\n% ls ~/.multica/…/hermes/memories  # owned by another user\n// after: remove the stale path as the daemon user, then re-run\n% sudo rm -rf ~/.multica/…/hermes/memories\n% multica daemon restart","handlingStrategy":"retry","validationCode":"// Before mounting, confirm the daemon can remove the stale path:\nif fi, err := os.Lstat(dst); err == nil && fi.IsDir() {\n    if err := os.RemoveAll(dst); err != nil {\n        log.Printf(\"pre-check failed, fix before task start: %v\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"// In the caller of mountHermesMemories:\nif err := mountHermesMemories(home, store, logger); err != nil {\n    if strings.Contains(err.Error(), \"remove stale memories path\") && isTransientFS(err) {\n        // single retry after brief backoff; EBUSY/AV locks often clear\n        time.Sleep(500 * time.Millisecond)\n        err = mountHermesMemories(home, store, logger)\n    }\n    if err != nil { return fmt.Errorf(\"overlay mount: %w\", err) }\n}","preventionTips":["Run only one daemon per Multica profile dir","Keep daemon and task overlays under the same OS user","Exclude the profile dir from antivirus on-access scanning"],"tags":["filesystem","hermes","migration","permissions"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}